package authenticateroute

import (
	"sync"
	"time"

	b64 "encoding/base64"

	"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
	"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
	"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
}

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

func (c *controller) handlePortal(ctx echo.Context) error {
	err := auth.ValidateAppKey(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	var user viewmodel.User
	if err = ctx.Bind(&user); err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	if user.Email == nil || len(*user.Email) == 0 || len(user.Pass) == 0 {
		return routeutils.ResponseAPIAuthError(ctx, "email and pass are required", false)
	}

	pass, err := b64.StdEncoding.DecodeString(user.Pass)
	if err != nil {
		return routeutils.ResponseAPIAuthError(ctx, "Invalid email or password", false)
	}
	user.Pass = string(pass)

	user, err = c.svc.Users.FullLogin("email", *user.Email, user.Pass, "SP")
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	if user.ID == "" {
		return routeutils.ResponseAPIAuthError(ctx, "Invalid email or password", false)
	}

	token, err := auth.GenerateToken(c.cfg, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	response := viewmodel.AuthResponse{
		Token:      token,
		ServerTime: time.Now().Unix(),
		ValidTime:  time.Now().Add(auth.TokenExpiration).Unix(),
		User:       user,
	}

	return routeutils.ResponseAPIOK(ctx, response)
}

func (c *controller) handleMember(ctx echo.Context) error {
	err := auth.ValidateAppKey(ctx, c.cfg)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	var user viewmodel.User
	if err = ctx.Bind(&user); err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	if user.PhoneNumber == nil || len(*user.PhoneNumber) == 0 || len(user.Pass) == 0 {
		return routeutils.ResponseAPIAuthError(ctx, "phonenumber and pass are required", false)
	}

	pass, err := b64.StdEncoding.DecodeString(user.Pass)
	if err != nil {
		return routeutils.ResponseAPIAuthError(ctx, "Invalid phonenumber or password", false)
	}
	user.Pass = string(pass)

	user, err = c.svc.Users.FullLogin("phone_number", *user.PhoneNumber, user.Pass, "US")
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	if user.ID == "" {
		return routeutils.ResponseAPIAuthError(ctx, "Invalid phonenumber or password", false)
	}

	token, err := auth.GenerateToken(c.cfg, user)
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	response := viewmodel.AuthResponse{
		Token:      token,
		ServerTime: time.Now().Unix(),
		ValidTime:  time.Now().Add(auth.TokenExpiration).Unix(),
		User:       user,
	}

	return routeutils.ResponseAPIOK(ctx, response)
}
