package handlers

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"strings"

	"aggios-app/backend/internal/api/middleware"
	"aggios-app/backend/internal/domain"
	"aggios-app/backend/internal/service"
)

// AuthHandler handles authentication endpoints
type AuthHandler struct {
	authService *service.AuthService
}

// NewAuthHandler creates a new auth handler
func NewAuthHandler(authService *service.AuthService) *AuthHandler {
	return &AuthHandler{
		authService: authService,
	}
}

// Register handles user registration
func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var req domain.CreateUserRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	user, err := h.authService.Register(req)
	if err != nil {
		switch err {
		case service.ErrEmailAlreadyExists:
			http.Error(w, err.Error(), http.StatusConflict)
		case service.ErrWeakPassword:
			http.Error(w, err.Error(), http.StatusBadRequest)
		default:
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(user)
}

// Login handles user login
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
	log.Printf("🔐 LOGIN HANDLER CALLED - Method: %s", r.Method)
	
	if r.Method != http.MethodPost {
		log.Printf("❌ Method not allowed: %s", r.Method)
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		log.Printf("❌ Failed to read body: %v", err)
		http.Error(w, "Failed to read request body", http.StatusBadRequest)
		return
	}
	defer r.Body.Close()

	log.Printf("📥 Raw body: %s", string(bodyBytes))

	// Trim whitespace to avoid decode errors caused by BOM or stray chars
	sanitized := strings.TrimSpace(string(bodyBytes))
	var req domain.LoginRequest
	if err := json.Unmarshal([]byte(sanitized), &req); err != nil {
		log.Printf("❌ JSON parse error: %v", err)
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	log.Printf("📧 Login attempt for email: %s", req.Email)

	response, err := h.authService.Login(req)
	if err != nil {
		log.Printf("❌ authService.Login error: %v", err)
		if err == service.ErrInvalidCredentials {
			http.Error(w, err.Error(), http.StatusUnauthorized)
		} else {
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	// VALIDAÇÃO DE SEGURANÇA: Verificar se o tenant do usuário corresponde ao subdomain acessado
	tenantIDFromContext := ""
	if ctxTenantID := r.Context().Value(middleware.TenantIDKey); ctxTenantID != nil {
		tenantIDFromContext, _ = ctxTenantID.(string)
	}

	// Se foi detectado um tenant no contexto (não é superadmin ou site institucional)
	if tenantIDFromContext != "" && response.User.TenantID != nil {
		userTenantID := response.User.TenantID.String()
		if userTenantID != tenantIDFromContext {
			log.Printf("❌ LOGIN BLOCKED: User from tenant %s tried to login in tenant %s subdomain",  userTenantID, tenantIDFromContext)
			http.Error(w, "Forbidden: Invalid credentials for this tenant", http.StatusForbidden)
			return
		}
		log.Printf("✅ TENANT LOGIN VALIDATION PASSED: %s", userTenantID)
	}

	log.Printf("✅ Login successful for %s, role=%s", response.User.Email, response.User.Role)
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// ChangePasswordRequest represents a password change request
type ChangePasswordRequest struct {
	CurrentPassword string `json:"currentPassword"`
	NewPassword     string `json:"newPassword"`
}

// ChangePassword handles password change
func (h *AuthHandler) ChangePassword(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Get user ID from context (set by auth middleware)
	userID, ok := r.Context().Value("userID").(string)
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	var req ChangePasswordRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	if req.CurrentPassword == "" || req.NewPassword == "" {
		http.Error(w, "Current password and new password are required", http.StatusBadRequest)
		return
	}

	// Call auth service to change password
	if err := h.authService.ChangePassword(userID, req.CurrentPassword, req.NewPassword); err != nil {
		if err == service.ErrInvalidCredentials {
			http.Error(w, "Current password is incorrect", http.StatusUnauthorized)
		} else if err == service.ErrWeakPassword {
			http.Error(w, "New password is too weak", http.StatusBadRequest)
		} else {
			http.Error(w, "Error changing password", http.StatusInternalServerError)
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]string{
		"message": "Password changed successfully",
	})
}

// UnifiedLogin handles login for all user types (agency, customer, superadmin)
func (h *AuthHandler) UnifiedLogin(w http.ResponseWriter, r *http.Request) {
	log.Printf("🔐 UNIFIED LOGIN HANDLER CALLED - Method: %s", r.Method)
	
	if r.Method != http.MethodPost {
		log.Printf("❌ Method not allowed: %s", r.Method)
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		log.Printf("❌ Failed to read body: %v", err)
		http.Error(w, "Failed to read request body", http.StatusBadRequest)
		return
	}
	defer r.Body.Close()

	log.Printf("📥 Raw body: %s", string(bodyBytes))

	sanitized := strings.TrimSpace(string(bodyBytes))
	var req domain.UnifiedLoginRequest
	if err := json.Unmarshal([]byte(sanitized), &req); err != nil {
		log.Printf("❌ JSON parse error: %v", err)
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	log.Printf("📧 Unified login attempt for email: %s", req.Email)

	response, err := h.authService.UnifiedLogin(req)
	if err != nil {
		log.Printf("❌ authService.UnifiedLogin error: %v", err)
		if err == service.ErrInvalidCredentials || strings.Contains(err.Error(), "não autorizado") {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{
				"error": err.Error(),
			})
		} else {
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	// VALIDAÇÃO DE SEGURANÇA: Verificar se o tenant corresponde ao subdomain acessado
	tenantIDFromContext := ""
	if ctxTenantID := r.Context().Value(middleware.TenantIDKey); ctxTenantID != nil {
		tenantIDFromContext, _ = ctxTenantID.(string)
	}

	// Se foi detectado um tenant no contexto E o usuário tem tenant
	if tenantIDFromContext != "" && response.TenantID != "" {
		if response.TenantID != tenantIDFromContext {
			log.Printf("❌ LOGIN BLOCKED: User from tenant %s tried to login in tenant %s subdomain", 
				response.TenantID, tenantIDFromContext)
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusForbidden)
			json.NewEncoder(w).Encode(map[string]string{
				"error": "Credenciais inválidas para esta agência",
			})
			return
		}
		log.Printf("✅ TENANT LOGIN VALIDATION PASSED: %s", response.TenantID)
	}

	log.Printf("✅ Unified login successful: email=%s, type=%s, role=%s", 
		response.Email, response.UserType, response.Role)
	
	// Montar resposta compatível com frontend antigo E com novos campos
	compatibleResponse := map[string]interface{}{
		"token": response.Token,
		"user": map[string]interface{}{
			"id":        response.UserID,
			"email":     response.Email,
			"name":      response.Name,
			"role":      response.Role,
			"tenant_id": response.TenantID,
			"user_type": response.UserType,
		},
		// Campos adicionais do sistema unificado
		"user_type": response.UserType,
		"user_id":   response.UserID,
		"subdomain": response.Subdomain,
		"tenant_id": response.TenantID,
	}
	
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(compatibleResponse)
}
