package validator

import (
	"errors"
	"strings"

	"eslogad-be/internal/constants"
	"eslogad-be/internal/contract"

	"github.com/google/uuid"
)

type UserValidatorImpl struct{}

func NewUserValidator() *UserValidatorImpl {
	return &UserValidatorImpl{}
}

func (v *UserValidatorImpl) ValidateCreateUserRequest(req *contract.CreateUserRequest) (error, string) {
	if req == nil {
		return errors.New("request body is required"), constants.MissingFieldErrorCode
	}

	if strings.TrimSpace(req.Email) == "" {
		return errors.New("email is required"), constants.MissingFieldErrorCode
	}

	if !isValidEmail(req.Email) {
		return errors.New("email format is invalid"), constants.MalformedFieldErrorCode
	}

	if strings.TrimSpace(req.Password) == "" {
		return errors.New("password is required"), constants.MissingFieldErrorCode
	}

	if len(req.Password) < 6 {
		return errors.New("password must be at least 6 characters"), constants.MalformedFieldErrorCode
	}

	if strings.TrimSpace(req.Role) == "" {
		return errors.New("role is required"), constants.MissingFieldErrorCode
	}

	if !isValidUserRole(req.Role) {
		return errors.New("invalid user role"), constants.MalformedFieldErrorCode
	}

	return nil, ""
}

func (v *UserValidatorImpl) ValidateUpdateUserRequest(req *contract.UpdateUserRequest) (error, string) {
	if req == nil {
		return errors.New("request body is required"), constants.MissingFieldErrorCode
	}

	if req.Email == nil && req.Role == nil && req.IsActive == nil {
		return errors.New("at least one field must be provided for update"), constants.MissingFieldErrorCode
	}

	if req.Email != nil {
		if strings.TrimSpace(*req.Email) == "" {
			return errors.New("email cannot be empty"), constants.MalformedFieldErrorCode
		}
		if !isValidEmail(*req.Email) {
			return errors.New("email format is invalid"), constants.MalformedFieldErrorCode
		}
	}

	if req.Role != nil {
		if strings.TrimSpace(*req.Role) == "" {
			return errors.New("role cannot be empty"), constants.MalformedFieldErrorCode
		}
		if !isValidUserRole(*req.Role) {
			return errors.New("invalid user role"), constants.MalformedFieldErrorCode
		}
	}

	return nil, ""
}

func (v *UserValidatorImpl) ValidateListUsersRequest(req *contract.ListUsersRequest) (error, string) {
	if req == nil {
		return errors.New("request is required"), constants.MissingFieldErrorCode
	}

	if req.Page <= 0 {
		return errors.New("page must be greater than 0"), constants.MalformedFieldErrorCode
	}

	if req.Limit <= 0 {
		return errors.New("limit must be greater than 0"), constants.MalformedFieldErrorCode
	}

	if req.Limit > 100 {
		return errors.New("limit cannot exceed 100"), constants.MalformedFieldErrorCode
	}

	if req.Role != nil && !isValidUserRole(*req.Role) {
		return errors.New("invalid user role filter"), constants.MalformedFieldErrorCode
	}

	return nil, ""
}

func (v *UserValidatorImpl) ValidateChangePasswordRequest(req *contract.ChangePasswordRequest) (error, string) {
	if req == nil {
		return errors.New("request body is required"), constants.MissingFieldErrorCode
	}

	if strings.TrimSpace(req.CurrentPassword) == "" {
		return errors.New("current_password is required"), constants.MissingFieldErrorCode
	}

	if strings.TrimSpace(req.NewPassword) == "" {
		return errors.New("new_password is required"), constants.MissingFieldErrorCode
	}

	if len(req.NewPassword) < 8 {
		return errors.New("new_password must be at least 8 characters"), constants.MalformedFieldErrorCode
	}

	if req.CurrentPassword == req.NewPassword {
		return errors.New("new password must be different from current password"), constants.MalformedFieldErrorCode
	}

	return nil, ""
}

func (v *UserValidatorImpl) ValidateUserID(userID uuid.UUID) (error, string) {
	if userID == uuid.Nil {
		return errors.New("user_id is required"), constants.MissingFieldErrorCode
	}

	return nil, ""
}

func isValidUserRole(role string) bool {
	validRoles := map[string]bool{
		string(constants.RoleAdmin):   true,
		string(constants.RoleManager): true,
		string(constants.RoleCashier): true,
		string(constants.RoleWaiter):  true,
	}
	return validRoles[role]
}

func (v *UserValidatorImpl) ValidateUpdateUserOutletRequest(req *contract.UpdateUserOutletRequest) (error, string) {
	if req.OutletID == uuid.Nil {
		return errors.New("outlet_id is required"), constants.MissingFieldErrorCode
	}

	return nil, ""
}
