package adminvalidator

import (
	"context"
	"fmt"

	"git.gocasts.ir/ebhomengo/niki/entity"
	errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
	validation "github.com/go-ozzo/ozzo-validation/v4"
)

const (
	phoneNumberRegex   = "^09\\d{9}$"
	minLengthFirstName = 3
	maxLengthFirstName = 40
	minLengthLastName  = 3
	maxLengthLastName  = 40
	minLengthPassword  = 8
	maxLengthPassword  = 32
)

//go:generate mockery --name Repository
type Repository interface {
	AdminExistByPhoneNumber(ctx context.Context, phoneNumber string) (bool, error)
	AdminExistByEmail(ctx context.Context, email string) (bool, error)
	GetAdminByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Admin, error)
}

type Validator struct {
	repo Repository
}

func New(repo Repository) Validator {
	return Validator{repo: repo}
}

func (v Validator) isAdminAllowed(ctx context.Context) func(interface{}) error {
	return func(value interface{}) error {
		phoneNumber, ok := value.(string)
		if !ok {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		admin, err := v.repo.GetAdminByPhoneNumber(ctx, phoneNumber)
		if err != nil {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		if admin.Status == entity.AdminInactiveStatus {
			return fmt.Errorf(errmsg.ErrorMsgAdminNotAllowed)
		}

		return nil
	}
}

func (v Validator) doesAdminExistByPhoneNumber(ctx context.Context) validation.RuleFunc {
	return func(value interface{}) error {
		phoneNumber, ok := value.(string)
		if !ok {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		adminExisted, err := v.repo.AdminExistByPhoneNumber(ctx, phoneNumber)
		if err != nil {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		if !adminExisted {
			return fmt.Errorf(errmsg.ErrorMsgPhoneNumberOrPassIsIncorrect)
		}

		return nil
	}
}

func (v Validator) IsPhoneNumberUnique(ctx context.Context) validation.RuleFunc {
	return func(value interface{}) error {
		phoneNumber, ok := value.(*string)
		if !ok {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		adminExisted, err := v.repo.AdminExistByPhoneNumber(ctx, *phoneNumber)
		if err != nil {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		if adminExisted {
			return fmt.Errorf(errmsg.ErrorMsgPhoneNumberIsNotUnique)
		}

		return nil
	}
}

func (v Validator) doesAdminExistByEmail(ctx context.Context) validation.RuleFunc {
	return func(value interface{}) error {
		email, ok := value.(*string)
		if !ok {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		adminExisted, err := v.repo.AdminExistByEmail(ctx, *email)
		if err != nil {
			return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
		}
		if adminExisted {
			return fmt.Errorf(errmsg.ErrorMsgEmailIsNotUnique)
		}

		return nil
	}
}

func (v Validator) IsRoleValid(value interface{}) error {
	role, ok := value.(*entity.AdminRole)
	if !ok {
		return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
	}

	if isValid := role.IsValid(); !isValid {
		return fmt.Errorf(errmsg.ErrorMsgInvalidInput)
	}

	return nil
}

func (v Validator) IsGenderValid(value interface{}) error {
	gender, ok := value.(*entity.Gender)
	if gender == nil {
		return nil
	}
	if !ok {
		return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
	}

	if isValid := gender.IsValid(); !isValid {
		return fmt.Errorf(errmsg.ErrorMsgInvalidInput)
	}

	return nil
}

func (v Validator) IsStatusValid(value interface{}) error {
	status, ok := value.(*entity.AdminStatus)
	if !ok {
		return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
	}

	if isValid := status.IsValid(); !isValid {
		return fmt.Errorf(errmsg.ErrorMsgInvalidInput)
	}

	return nil
}
