package api

import (
	"log"
	"sync"
	"time"
	"net/http"

	"github.com/labstack/echo/v4"

	"sku61.com/InvestAccnt/api/gen"
	"sku61.com/InvestAccnt/api/authn51"
)


type BianApiService struct {
	Lock   sync.Mutex
	StartTime time.Time
	Configuration SoftwareConfiguration
	Authn *authn51.Authn51
	DataFolder string
	StatusCode int
}

func NewMicroService(serverConfig SoftwareConfiguration) (*BianApiService, error) {
	
	var microservice = BianApiService{
		StartTime: time.Now(),
		DataFolder: serverConfig.Folders.Data,
		StatusCode: 200,
	}

	microservice.Configuration = serverConfig
	aut, err := authn51.NewAuthn51(serverConfig.GetConfigurationFile())
	if (err != nil) {
		log.Printf("Error creating Authn51: %v", err)
	}
	microservice.Authn = aut

	if (microservice.Configuration.Support.Level > 2) {
		log.Printf("Base path: %s", microservice.Configuration.Server.BasePath)
	}
	
	// Prime the security
	if (!microservice.IsProductionEnvironment()) {
		token, _ := microservice.Authn.CreateToken(microservice.Authn.Bearer.DefaultUser)
		log.Printf("token: %s", token)
	}

	return &microservice, nil
}


func sendGeneralErrorBrief(ctx echo.Context, code int, message string) error {
	return sendGeneralError(ctx, code, message, "", "", "")
}


func sendGeneralError(ctx echo.Context, code int, message string, status string, resolution string, technical string) error {

	generalError := gen.ErrorModel{
		Message:    &message,
		Status:     &status,
		Resolution: &resolution,
		Technical: 	&technical,
	}

	return ctx.JSON(code, generalError)
}

func setLinkBrief(href string, rel string) gen.LinksModel {
	
	mt := "application/json"
	op := gen.GET

	return setLink(href, rel, mt, op, "")
}

func setLink(href string, rel string, mediaType string, operation gen.LinksModelOperation, caption string) gen.LinksModel {

	linkHref := href
	linkRel := rel

	mt := mediaType
	if (mt == "") {
		mt = "application/json"
	}
	op := operation
	if (op == "") {
		op = gen.GET
	}
	cap := caption

	var link = gen.LinksModel {	
		Href: linkHref,
		MediaType: &mt,
		Rel: linkRel,
		Operation: &op,
		Caption: &cap,
	}

	return link
}


func (microservice *BianApiService) IsProductionEnvironment() bool {

	if (microservice.Configuration.Environment == "development" || microservice.Configuration.Environment == "testing") {
		return false
	} else {
		return true
	}

}

func (self *BianApiService) RegisterHandlers(e *echo.Echo)  {

	gen.RegisterHandlersWithBaseURL(e, self, self.Configuration.Server.BasePath)

	if (!self.IsProductionEnvironment()) {
		if (self.Configuration.Support.Level > 2) {
			log.Print("Enabling non production routes for debugging")
		}
		e.Static((self.Configuration.Server.BasePath+ "/"), self.Configuration.Folders.Static)
		e.GET((self.Configuration.Server.BasePath+ "/authn/new-token"), self.NewToken)
		e.GET((self.Configuration.Server.BasePath+ "/authn/refresh-token"), self.RefreshToken)
	}

	if (self.Configuration.Support.Level > 2) {
		log.Print("Echo routes are:")
		for _, route := range e.Routes() {
			log.Printf("    Route: %s %s %s", route.Method, route.Path, route.Name)
		}
	}

	
}

func (self *BianApiService) BrowseSkipper(path string) bool {
	if (!self.IsProductionEnvironment()) {
		return browseSkipper(self.Configuration.Server.BasePath, path)
	} else {
		return false
	}
}

func (self *BianApiService) NewToken(ctx echo.Context) error {

	if (self.IsProductionEnvironment()) {
		return ctx.JSON(http.StatusForbidden, "")
	} else {
		token, _ := self.Authn.CreateToken(self.Authn.Bearer.DefaultUser)
		log.Printf("New token: %s", token)

		return ctx.JSON(http.StatusOK, token)
	}
}

func (self *BianApiService) RefreshToken(ctx echo.Context) error {

	if (self.IsProductionEnvironment()) {
		return ctx.JSON(http.StatusForbidden, "")
	} else {
		ad, err := self.Authn.ExtractTokenMetadata(ctx.Request())
		if (err != nil) {
			return ctx.JSON(http.StatusBadRequest, "")
		} else {
			token, _ := self.Authn.CreateToken(ad.UserId)
			log.Printf("Refresh token: %s \n %s", ad.UserId, token )

			return ctx.JSON(http.StatusOK, token)
		}
	}
}


