package auth

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"go.uber.org/zap"

	"github.com/RyanCopley/skybridge/kms/internal/config"
	"github.com/RyanCopley/skybridge/kms/internal/errors"
)

// HeaderValidator provides secure validation of authentication headers
type HeaderValidator struct {
	config config.ConfigProvider
	logger *zap.Logger
}

// NewHeaderValidator creates a new header validator
func NewHeaderValidator(config config.ConfigProvider, logger *zap.Logger) *HeaderValidator {
	return &HeaderValidator{
		config: config,
		logger: logger,
	}
}

// ValidatedUserContext holds validated user information
type ValidatedUserContext struct {
	UserID    string
	Email     string
	Timestamp time.Time
	Signature string
}

// ValidateAuthenticationHeaders validates user authentication headers with HMAC signature
func (hv *HeaderValidator) ValidateAuthenticationHeaders(r *http.Request) (*ValidatedUserContext, error) {
	userEmail := r.Header.Get(hv.config.GetString("AUTH_HEADER_USER_EMAIL"))
	timestamp := r.Header.Get("X-Auth-Timestamp")
	signature := r.Header.Get("X-Auth-Signature")

	if userEmail == "" {
		hv.logger.Warn("Missing user email header")
		return nil, errors.NewAuthenticationError("User authentication required")
	}

	// In development mode, skip signature validation for trusted headers
	if hv.config.IsDevelopment() {
		hv.logger.Debug("Development mode: skipping signature validation", 
			zap.String("user_email", userEmail))
	} else {
		// Production mode: require full signature validation
		if timestamp == "" || signature == "" {
			hv.logger.Warn("Missing authentication signature headers", 
				zap.String("user_email", userEmail))
			return nil, errors.NewAuthenticationError("Authentication signature required")
		}

		// Validate timestamp (prevent replay attacks)
		timestampInt, err := strconv.ParseInt(timestamp, 10, 64)
		if err != nil {
			hv.logger.Warn("Invalid timestamp format", 
				zap.String("timestamp", timestamp),
				zap.String("user_email", userEmail))
			return nil, errors.NewAuthenticationError("Invalid timestamp format")
		}

		timestampTime := time.Unix(timestampInt, 0)
		now := time.Now()
		
		// Allow 5 minutes clock skew
		maxAge := 5 * time.Minute
		if now.Sub(timestampTime) > maxAge || timestampTime.After(now.Add(1*time.Minute)) {
			hv.logger.Warn("Timestamp outside acceptable window", 
				zap.Time("timestamp", timestampTime),
				zap.Time("now", now),
				zap.String("user_email", userEmail))
			return nil, errors.NewAuthenticationError("Request timestamp outside acceptable window")
		}

		// Validate HMAC signature
		if !hv.validateSignature(userEmail, timestamp, signature) {
			hv.logger.Warn("Invalid authentication signature", 
				zap.String("user_email", userEmail))
			return nil, errors.NewAuthenticationError("Invalid authentication signature")
		}
	}

	// Validate email format
	if !hv.isValidEmail(userEmail) {
		hv.logger.Warn("Invalid email format", 
			zap.String("user_email", userEmail))
		return nil, errors.NewAuthenticationError("Invalid email format")
	}

	hv.logger.Debug("Authentication headers validated successfully", 
		zap.String("user_email", userEmail))

	// Set defaults for development mode
	var timestampTime time.Time
	var signatureValue string
	
	if hv.config.IsDevelopment() {
		timestampTime = time.Now()
		signatureValue = "dev-mode-bypass"
	} else {
		timestampInt, _ := strconv.ParseInt(timestamp, 10, 64)
		timestampTime = time.Unix(timestampInt, 0)
		signatureValue = signature
	}

	return &ValidatedUserContext{
		UserID:    userEmail,
		Email:     userEmail,
		Timestamp: timestampTime,
		Signature: signatureValue,
	}, nil
}

// validateSignature validates the HMAC signature
func (hv *HeaderValidator) validateSignature(userEmail, timestamp, signature string) bool {
	// Get the signing key from config
	signingKey := hv.config.GetString("AUTH_SIGNING_KEY")
	if signingKey == "" {
		hv.logger.Error("AUTH_SIGNING_KEY not configured")
		return false
	}

	// Create the signing string
	signingString := fmt.Sprintf("%s:%s", userEmail, timestamp)
	
	// Calculate expected signature
	mac := hmac.New(sha256.New, []byte(signingKey))
	mac.Write([]byte(signingString))
	expectedSignature := hex.EncodeToString(mac.Sum(nil))

	// Use constant-time comparison to prevent timing attacks
	return hmac.Equal([]byte(signature), []byte(expectedSignature))
}

// isValidEmail performs basic email validation
func (hv *HeaderValidator) isValidEmail(email string) bool {
	if len(email) == 0 || len(email) > 254 {
		return false
	}

	// Basic email validation - contains @ and has valid structure
	parts := strings.Split(email, "@")
	if len(parts) != 2 {
		return false
	}

	local, domain := parts[0], parts[1]
	
	// Local part validation
	if len(local) == 0 || len(local) > 64 {
		return false
	}

	// Domain part validation
	if len(domain) == 0 || len(domain) > 253 {
		return false
	}

	if !strings.Contains(domain, ".") {
		return false
	}

	// Check for invalid characters (basic check)
	invalidChars := []string{" ", "..", "@@", "<", ">", "\"", "'"}
	for _, char := range invalidChars {
		if strings.Contains(email, char) {
			return false
		}
	}

	return true
}

// GenerateSignatureExample generates an example signature for documentation
func (hv *HeaderValidator) GenerateSignatureExample(userEmail string, timestamp string, signingKey string) string {
	signingString := fmt.Sprintf("%s:%s", userEmail, timestamp)
	mac := hmac.New(sha256.New, []byte(signingKey))
	mac.Write([]byte(signingString))
	return hex.EncodeToString(mac.Sum(nil))
}