package providerroute

import (
	"sync"

	"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
	"bitbucket.org/nemt/nemt-portal-api/application/third/npd"
	"bitbucket.org/nemt/nemt-portal-api/application/third/npd/npdmodel"
	"bitbucket.org/nemt/nemt-portal-api/infra/auth"
	"bitbucket.org/nemt/nemt-portal-api/infra/config"
	"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
	"github.com/labstack/echo"
)

var (
	instance *controller
	once     sync.Once
)

type controller struct {
	cfg *config.Config
	svc *applicationservice.Service
	npd *npd.Service
}

func controllerInstance(cfg *config.Config, svc *applicationservice.Service) *controller {
	once.Do(func() {
		instance = &controller{
			cfg: cfg,
			svc: svc,
			npd: npd.New(cfg),
		}
	})
	return instance
}

func (c *controller) handle(ctx echo.Context) error {
	var providers []npdmodel.ProviderResponse

	if err := ctx.Bind(&providers); err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	authUser, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	entities, err := c.svc.Provider.Save(providers, authUser)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, entities)
}

func (c *controller) handleParticipating(ctx echo.Context) error {
	query := ctx.QueryParam("query")
	var lat float64
	var long float64
	var distance int64
	distance = 10
	planCode := ""
	productID := ""
	mukID := ""
	providerID := ""
	sort := "distance"

	lat, err := routeutils.GetAndValidateFloatQueryParam(ctx, "lat", "latitude is mandatory")
	if err != nil {
		lat = 0
	}

	long, err = routeutils.GetAndValidateFloatQueryParam(ctx, "long", "longitude is mandatory")
	if err != nil {
		long = 0
	}

	planCode, _ = routeutils.GetAndValidateStringQueryParam(ctx, "plan_code", "Plan Code is mandatory")
	productID, _ = routeutils.GetAndValidateStringQueryParam(ctx, "product_id", "Product ID is mandatory")

	providerID, _ = routeutils.GetAndValidateStringQueryParam(ctx, "provider_id", "Provider ID is mandatory")
	distance, err = routeutils.GetAndValidateIntQueryParam(ctx, "distance", "distance is mandatory")
	if err != nil {
		distance = 1000000
	}

	sort, err = routeutils.GetAndValidateStringQueryParam(ctx, "sort", "sort is mandatory")
	if err != nil || (sort != "distance" && sort != "name") {
		sort = "distance"
	}

	mukID, _ = routeutils.GetAndValidateStringQueryParam(ctx, "muk_id", "Muk ID is mandatory")

	authUser, err := auth.GetUserDetail(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	// if (lat != 0 && long == 0) || (lat == 0 && long != 0) {
	// 	return routeutils.ResponseAPIFieldValidationError(ctx, "coordinates", "Invalid coordinates")
	// } else {
	// 	lat = 41.886406
	// 	long = -87.624225
	// }

	lat = 41.819078
	long = -87.623129

	if len(mukID) > 0 {
		query = ""
		providerID = ""
	}

	providers, err := c.svc.Provider.Get(query, lat, long, distance, planCode, productID, mukID, providerID, sort, authUser)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, providers)
}

func (c *controller) handleList(ctx echo.Context) error {
	name := ctx.QueryParam("name")
	searchBy := ctx.QueryParam("searchBy")

	lat, err := routeutils.GetAndValidateFloatQueryParam(ctx, "lat", "latitude is required")
	if err != nil {
		return err
	}

	long, err := routeutils.GetAndValidateFloatQueryParam(ctx, "long", "longitude is required")
	if err != nil {
		return err
	}

	distance, err := routeutils.GetAndValidateIntQueryParam(ctx, "distance", "distance is required")
	if err != nil {
		distance = 10
	}

	limit, err := routeutils.GetAndValidateIntQueryParam(ctx, "limit", "limit is required")
	if err != nil {
		limit = 50
	}

	sortBy, err := routeutils.GetAndValidateStringQueryParam(ctx, "sortby", "limit is required")
	if err != nil || (sortBy != "distance" && sortBy != "name") {
		sortBy = "distance"
	}

	providerParams := npdmodel.ProviderSearchParams{
		Name:                      name,
		SearchBy:                  searchBy,
		Latitude:                  lat,
		Longitude:                 long,
		Distance:                  distance,
		Limit:                     limit,
		Offset:                    0,
		SortBy:                    sortBy,
		FacetAcceptNewPatients:    "Y",
		FacetExtendedOfficeHours:  "Y",
		FacetGender:               "Y",
		FacetHospitalAffiliations: "Y",
		FacetLanguage:             "Y",
		FacetOfficeLanguages:      "Y",
		FacetProviderAffiliations: "Y",
		FacetProviderEntityName:   "Y",
		FacetSummaryScore:         "Y",
	}

	providers, err := c.npd.Provider.GetProviders(providerParams)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	return routeutils.ResponseAPIOK(ctx, providers)
}
