package selfregisterroute

import (
	"fmt"
	"strings"
	"sync"

	b64 "encoding/base64"

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

const (
	notificationEmailSubject = "Registration sucessful"
	notificationEmailBody    = "You have registered as a Visit Reporter for CHM NEMT.\nLogin: https://portal.bcbsinstitute.com\nReset PW: https://portal.bcbsinstitute.com/forgot"
	notificationSmsBody      = "You have registered as a Visit Reporter for CHM NEMT. Login: https://portal.bcbsinstitute.com  Reset PW: https://portal.bcbsinstitute.com/forgot"
)

const (
	phoneNumberMaxLength = 12
)

var (
	instance *controller
	once     sync.Once
)

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

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

func removeNonNumberChars(input string) string {
	result := ""
	for _, char := range input {
		if char >= '0' && char <= '9' {
			result += string(char)
		}
	}

	return result
}

func (c *controller) handle(ctx echo.Context) error {
	var user viewmodel.User
	if err := ctx.Bind(&user); err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

	//format phone number - max length in database is 12 chars
	formatedPhoneNumber := strings.TrimSpace(*user.PhoneNumber)
	formatedPhoneNumber = strings.Replace(formatedPhoneNumber, "+1", "", -1)
	formatedPhoneNumber = removeNonNumberChars(formatedPhoneNumber)

	if len(formatedPhoneNumber) > phoneNumberMaxLength {
		formatedPhoneNumber = formatedPhoneNumber[:phoneNumberMaxLength]
	}

	*user.PhoneNumber = formatedPhoneNumber

	authUser, err := c.svc.Users.GetByUUID("573c70ff-733d-11e7-ba8f-0a6ad3fcdeaa", "")
	if err != nil {
		return routeutils.HandleAPIError(ctx, err)
	}

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

	if validationErrors := validation.ValidateSelfregistration(&user); len(validationErrors) > 0 {
		return routeutils.ResponseAPICustomValidationError(ctx, "Self registration failed", validationErrors)
	}

	if len(user.First) != 0 && len(user.Last) != 0 {
		user.Name = fmt.Sprintf("%s %s", user.First, user.Last)
	}

	provider, err := c.svc.Provider.GetByNPI(user.Provider.InternalID, authUser)
	if err != nil {
		fmt.Println("Error to create organization", err)
		return routeutils.HandleAPIError(ctx, err)
	}

	var organization viewmodel.Organization
	if provider.ProviderUUID == "" {
		org := viewmodel.Organization{
			Author:     authUser,
			LastEditor: authUser,
			Name:       user.Provider.OrganizatioName,
			Type: viewmodel.OrganizationType{
				Key:  "provider",
				Name: "Provider",
			},
			Reference: npdmodel.ProviderResponse{
				OrgName: user.Provider.OrganizatioName,
				FivePartKeyGroups: []npdmodel.PartKeyGroup{
					npdmodel.PartKeyGroup{
						ProviderNum: user.Provider.InternalID,
					},
				},
			},
		}

		organization, err = c.svc.Organization.AddOrganization(org, authUser)
		if err != nil {
			fmt.Println("Error to create organization", err)
			return routeutils.HandleAPIError(ctx, err)
		}

		if organization.UUID == "" {
			return routeutils.ResponseAPIValidationError(ctx, "Error to create organization")
		}
	} else {
		organization = provider.Organization
	}

	user.Organizations = []viewmodel.Organization{organization}
	user.Profiles = []viewmodel.Profile{viewmodel.Profile{
		Name:         "Visit Reporter",
		Key:          "VIRPT",
		Organization: organization,
	}}

	user, err = c.svc.Users.Create(user, authUser)
	if err != nil {
		fmt.Println("Error to create user", err)
		return routeutils.HandleAPIError(ctx, err)
	}

	//Send email notification to Authorized user
	notification := viewmodel.Notification{
		Type:    applicationservice.NotificationTypeEmail,
		From:    c.cfg.Email.Sender,
		To:      *user.Email,
		Subject: notificationEmailSubject,
		Message: notificationEmailBody,
	}

	notification, err = c.svc.Notification.SendNotificationWithoutWritingToDatabase(notification)
	if err != nil {
		logger := ctx.Logger()
		logger.Warnf("Application Error: Could not send email notification to user email : %s", *user.Email)
	}

	//Send sms notification to Authorized user

	formatedPhoneNumber = *user.PhoneNumber

	notification = viewmodel.Notification{
		Type:    applicationservice.NOtificationTypeSMS,
		To:      *user.PhoneNumber,
		Message: notificationSmsBody,
	}

	notification, err = c.svc.Notification.SendNotificationWithoutWritingToDatabase(notification)
	if err != nil {
		logger := ctx.Logger()
		logger.Warnf("Application Error: Could not send sms notification to user mobile : %s", *user.PhoneNumber)
	}

	return routeutils.ResponseAPIOK(ctx, user)
}
