package user

import (
	"errors"
	"regexp"
	"time"
)

// User represents a user entity in the domain
// Every user strictly belongs to a tenant
type User struct {
	ID          string
	Email       string
	FirstName   string
	LastName    string
	Name        string
	LexicalName string
	Timezone    string

	// Role management
	Role int

	// State management
	Status int

	// Embedded structs for better organization
	ProfileData *UserProfileData

	// Encapsulating security related data
	SecurityData *UserSecurityData

	// Metadata about the user
	Metadata *UserMetadata

	// Limited metadata fields used for querying
	TenantID  string // Every user belongs to a tenant
	CreatedAt time.Time
	UpdatedAt time.Time
}

// UserProfileData contains user profile information
type UserProfileData struct {
	Phone                                          string
	Country                                        string
	Region                                         string
	City                                           string
	PostalCode                                     string
	AddressLine1                                   string
	AddressLine2                                   string
	HasShippingAddress                             bool
	ShippingName                                   string
	ShippingPhone                                  string
	ShippingCountry                                string
	ShippingRegion                                 string
	ShippingCity                                   string
	ShippingPostalCode                             string
	ShippingAddressLine1                           string
	ShippingAddressLine2                           string
	Timezone                                       string
	AgreeTermsOfService                            bool
	AgreePromotions                                bool
	AgreeToTrackingAcrossThirdPartyAppsAndServices bool
}

// UserMetadata contains audit and tracking information
type UserMetadata struct {
	// CWE-359: Encrypted IP addresses for GDPR compliance
	CreatedFromIPAddress    string    // Encrypted with go-ipcrypt
	CreatedFromIPTimestamp  time.Time // For 90-day expiration tracking
	CreatedByUserID         string
	CreatedAt               time.Time
	CreatedByName           string
	ModifiedFromIPAddress   string    // Encrypted with go-ipcrypt
	ModifiedFromIPTimestamp time.Time // For 90-day expiration tracking
	ModifiedByUserID        string
	ModifiedAt              time.Time
	ModifiedByName          string
	LastLoginAt             time.Time
}

// FullName returns the user's full name computed from FirstName and LastName
func (u *User) FullName() string {
	if u.FirstName == "" && u.LastName == "" {
		return u.Name // Fallback to Name field if first/last are empty
	}
	return u.FirstName + " " + u.LastName
}

// UserSecurityData contains security-related information
type UserSecurityData struct {
	PasswordHashAlgorithm string
	PasswordHash          string

	WasEmailVerified bool
	Code             string
	CodeType         string // 'email_verification' or 'password_reset'
	CodeExpiry       time.Time

	// OTPEnabled controls whether we force 2FA or not during login
	OTPEnabled bool

	// OTPVerified indicates user has successfully validated their OTP token after enabling 2FA
	OTPVerified bool

	// OTPValidated automatically gets set as `false` on successful login and then sets `true` once successfully validated by 2FA
	OTPValidated bool

	// OTPSecret the unique one-time password secret to be shared between our backend and 2FA authenticator apps
	OTPSecret string

	// OTPAuthURL is the URL used to share
	OTPAuthURL string

	// OTPBackupCodeHash is the one-time use backup code which resets the 2FA settings
	OTPBackupCodeHash string

	// OTPBackupCodeHashAlgorithm tracks the hashing algorithm used
	OTPBackupCodeHashAlgorithm string
}

// Domain errors
var (
	ErrUserNotFound           = errors.New("user not found")
	ErrInvalidEmail           = errors.New("invalid email format")
	ErrEmailRequired          = errors.New("email is required")
	ErrFirstNameRequired      = errors.New("first name is required")
	ErrLastNameRequired       = errors.New("last name is required")
	ErrNameRequired           = errors.New("name is required")
	ErrTenantIDRequired       = errors.New("tenant ID is required")
	ErrPasswordRequired       = errors.New("password is required")
	ErrPasswordTooShort       = errors.New("password must be at least 8 characters")
	ErrPasswordTooWeak        = errors.New("password must contain uppercase, lowercase, number, and special character")
	ErrRoleRequired           = errors.New("role is required")
	ErrUserAlreadyExists      = errors.New("user already exists")
	ErrInvalidCredentials     = errors.New("invalid credentials")
	ErrTermsOfServiceRequired = errors.New("must agree to terms of service")
)

// Email validation regex (basic)
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)

// Validate validates the user entity
func (u *User) Validate() error {
	if u.TenantID == "" {
		return ErrTenantIDRequired
	}

	if u.Email == "" {
		return ErrEmailRequired
	}

	if !emailRegex.MatchString(u.Email) {
		return ErrInvalidEmail
	}

	if u.Name == "" {
		return ErrNameRequired
	}

	// Validate ProfileData if present
	if u.ProfileData != nil {
		// Terms of Service is REQUIRED
		if !u.ProfileData.AgreeTermsOfService {
			return ErrTermsOfServiceRequired
		}
	}

	return nil
}
