// File Path: monorepo/cloud/maplepress-backend/internal/interface/http/dto/gateway/register_dto.go
package gateway

import (
	"fmt"
	"time"

	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/validation"
)

// RegisterRequest is the HTTP request for user registration
type RegisterRequest struct {
	Email           string `json:"email"`
	Password        string `json:"password"`
	ConfirmPassword string `json:"confirm_password"`
	FirstName       string `json:"first_name"`
	LastName        string `json:"last_name"`
	TenantName      string `json:"tenant_name"`
	Timezone        string `json:"timezone,omitempty"` // Optional: defaults to "UTC" if not provided

	// Consent fields
	AgreeTermsOfService                            bool `json:"agree_terms_of_service"`
	AgreePromotions                                bool `json:"agree_promotions"`
	AgreeToTrackingAcrossThirdPartyAppsAndServices bool `json:"agree_to_tracking_across_third_party_apps_and_services"`
}

// ValidationErrors represents validation errors in RFC 9457 format
type ValidationErrors struct {
	Errors map[string][]string
}

// Error implements the error interface
func (v *ValidationErrors) Error() string {
	if len(v.Errors) == 0 {
		return ""
	}
	// For backward compatibility with error logging, format as string
	var messages []string
	for field, errs := range v.Errors {
		for _, err := range errs {
			messages = append(messages, fmt.Sprintf("%s: %s", field, err))
		}
	}
	return fmt.Sprintf("validation errors: %v", messages)
}

// Validate validates the registration request fields
// CWE-20: Improper Input Validation - Comprehensive email validation and normalization
// Returns all validation errors grouped together in RFC 9457 format
func (r *RegisterRequest) Validate() error {
	v := validation.NewValidator()
	emailValidator := validation.NewEmailValidator()
	validationErrors := make(map[string][]string)

	// Validate and normalize email
	normalizedEmail, err := emailValidator.ValidateAndNormalize(r.Email, "email")
	if err != nil {
		// Extract just the error message without the field name prefix
		errMsg := extractErrorMessage(err.Error())
		validationErrors["email"] = append(validationErrors["email"], errMsg)
	} else {
		r.Email = normalizedEmail
	}

	// Validate password (non-empty, will be validated for strength in use case)
	if err := v.ValidateRequired(r.Password, "password"); err != nil {
		errMsg := extractErrorMessage(err.Error())
		validationErrors["password"] = append(validationErrors["password"], errMsg)
	} else if err := v.ValidateLength(r.Password, "password", 8, 128); err != nil {
		errMsg := extractErrorMessage(err.Error())
		validationErrors["password"] = append(validationErrors["password"], errMsg)
	}

	// Validate confirm password
	if err := v.ValidateRequired(r.ConfirmPassword, "confirm_password"); err != nil {
		errMsg := extractErrorMessage(err.Error())
		validationErrors["confirm_password"] = append(validationErrors["confirm_password"], errMsg)
	} else if r.Password != r.ConfirmPassword {
		// Only check if passwords match if both are provided
		validationErrors["confirm_password"] = append(validationErrors["confirm_password"], "Passwords do not match")
	}

	// Validate first name
	firstName, err := v.ValidateAndSanitizeString(r.FirstName, "first_name", 1, 100)
	if err != nil {
		errMsg := extractErrorMessage(err.Error())
		validationErrors["first_name"] = append(validationErrors["first_name"], errMsg)
	} else {
		r.FirstName = firstName
		if err := v.ValidateNoHTML(r.FirstName, "first_name"); err != nil {
			errMsg := extractErrorMessage(err.Error())
			validationErrors["first_name"] = append(validationErrors["first_name"], errMsg)
		}
	}

	// Validate last name
	lastName, err := v.ValidateAndSanitizeString(r.LastName, "last_name", 1, 100)
	if err != nil {
		errMsg := extractErrorMessage(err.Error())
		validationErrors["last_name"] = append(validationErrors["last_name"], errMsg)
	} else {
		r.LastName = lastName
		if err := v.ValidateNoHTML(r.LastName, "last_name"); err != nil {
			errMsg := extractErrorMessage(err.Error())
			validationErrors["last_name"] = append(validationErrors["last_name"], errMsg)
		}
	}

	// Validate tenant name
	tenantName, err := v.ValidateAndSanitizeString(r.TenantName, "tenant_name", 1, 100)
	if err != nil {
		errMsg := extractErrorMessage(err.Error())
		validationErrors["tenant_name"] = append(validationErrors["tenant_name"], errMsg)
	} else {
		r.TenantName = tenantName
		if err := v.ValidateNoHTML(r.TenantName, "tenant_name"); err != nil {
			errMsg := extractErrorMessage(err.Error())
			validationErrors["tenant_name"] = append(validationErrors["tenant_name"], errMsg)
		}
	}

	// Validate consent: Terms of Service is REQUIRED
	if !r.AgreeTermsOfService {
		validationErrors["agree_terms_of_service"] = append(validationErrors["agree_terms_of_service"], "Must agree to terms of service")
	}

	// Note: AgreePromotions and AgreeToTrackingAcrossThirdPartyAppsAndServices
	// are optional (defaults to false if not provided)

	// Return all errors grouped together in RFC 9457 format
	if len(validationErrors) > 0 {
		return &ValidationErrors{Errors: validationErrors}
	}

	return nil
}

// extractErrorMessage extracts the error message after the field name prefix
// Example: "email: invalid email format" -> "Invalid email format"
func extractErrorMessage(fullError string) string {
	// Find the colon separator
	colonIndex := -1
	for i, char := range fullError {
		if char == ':' {
			colonIndex = i
			break
		}
	}

	if colonIndex == -1 {
		// No colon found, capitalize first letter and return
		if len(fullError) > 0 {
			return string(fullError[0]-32) + fullError[1:]
		}
		return fullError
	}

	// Extract message after colon and trim spaces
	message := fullError[colonIndex+1:]
	if len(message) > 0 && message[0] == ' ' {
		message = message[1:]
	}

	// Capitalize first letter
	if len(message) > 0 {
		firstChar := message[0]
		if firstChar >= 'a' && firstChar <= 'z' {
			message = string(firstChar-32) + message[1:]
		}
	}

	return message
}

// RegisterResponse is the HTTP response after successful registration
type RegisterResponse struct {
	// User details
	UserID    string `json:"user_id"`
	UserEmail string `json:"user_email"`
	UserName  string `json:"user_name"`
	UserRole  string `json:"user_role"`

	// Tenant details
	TenantID   string `json:"tenant_id"`
	TenantName string `json:"tenant_name"`
	TenantSlug string `json:"tenant_slug"`

	// Authentication tokens
	SessionID     string    `json:"session_id"`
	AccessToken   string    `json:"access_token"`
	AccessExpiry  time.Time `json:"access_expiry"`
	RefreshToken  string    `json:"refresh_token"`
	RefreshExpiry time.Time `json:"refresh_expiry"`

	CreatedAt time.Time `json:"created_at"`
}
