package handlers

import (
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"time"

	"aggios-app/backend/internal/config"
	"aggios-app/backend/internal/domain"
	"aggios-app/backend/internal/service"

	"github.com/golang-jwt/jwt/v5"
	"github.com/gorilla/mux"
	"github.com/google/uuid"
)

// AgencyRegistrationHandler handles agency management endpoints
type AgencyRegistrationHandler struct {
	agencyService *service.AgencyService
	cfg           *config.Config
}

// NewAgencyRegistrationHandler creates a new agency registration handler
func NewAgencyRegistrationHandler(agencyService *service.AgencyService, cfg *config.Config) *AgencyRegistrationHandler {
	return &AgencyRegistrationHandler{
		agencyService: agencyService,
		cfg:           cfg,
	}
}

// RegisterAgency handles agency registration (SUPERADMIN only)
func (h *AgencyRegistrationHandler) RegisterAgency(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var req domain.RegisterAgencyRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		log.Printf("❌ Error decoding request: %v", err)
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	log.Printf("📥 Registering agency: %s (subdomain: %s)", req.AgencyName, req.Subdomain)
	log.Printf("📊 Payload received: RazaoSocial=%s, Phone=%s, City=%s, State=%s, Neighborhood=%s, TeamSize=%s, PrimaryColor=%s, SecondaryColor=%s", 
		req.RazaoSocial, req.Phone, req.City, req.State, req.Neighborhood, req.TeamSize, req.PrimaryColor, req.SecondaryColor)

	tenant, admin, err := h.agencyService.RegisterAgency(req)
	if err != nil {
		log.Printf("❌ Error registering agency: %v", err)
		switch err {
		case service.ErrSubdomainTaken:
			http.Error(w, err.Error(), http.StatusConflict)
		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
	}

	log.Printf("✅ Agency created: %s (ID: %s)", tenant.Name, tenant.ID)

	// Generate JWT token for the new admin
	claims := jwt.MapClaims{
		"user_id":   admin.ID.String(),
		"email":     admin.Email,
		"role":      admin.Role,
		"tenant_id": tenant.ID.String(),
		"exp":       time.Now().Add(time.Hour * 24 * 7).Unix(), // 7 days
		"iat":       time.Now().Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString([]byte(h.cfg.JWT.Secret))
	if err != nil {
		http.Error(w, "Failed to generate token", http.StatusInternalServerError)
		return
	}

	protocol := "http://"
	if h.cfg.App.Environment == "production" {
		protocol = "https://"
	}

	response := map[string]interface{}{
		"token":      tokenString,
		"id":         admin.ID,
		"email":      admin.Email,
		"name":       admin.Name,
		"role":       admin.Role,
		"tenantId":   tenant.ID,
		"company":    tenant.Name,
		"subdomain":  tenant.Subdomain,
		"message":    "Agency registered successfully",
		"access_url": protocol + tenant.Domain,
	}

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

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

	var req domain.PublicRegisterAgencyRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		log.Printf("❌ Error decoding request: %v", err)
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	log.Printf("📥 Public Registering agency: %s (subdomain: %s)", req.CompanyName, req.Subdomain)
	log.Printf("📦 Full Payload: %+v", req)

	// Map to internal request
	phone := ""
	if len(req.Contacts) > 0 {
		phone = req.Contacts[0].Whatsapp
	}

	internalReq := domain.RegisterAgencyRequest{
		AgencyName:     req.CompanyName,
		Subdomain:      req.Subdomain,
		CNPJ:           req.CNPJ,
		RazaoSocial:    req.RazaoSocial,
		Description:    req.Description,
		Website:        req.Website,
		Industry:       req.Industry,
		Phone:          phone,
		TeamSize:       req.TeamSize,
		CEP:            req.CEP,
		State:          req.State,
		City:           req.City,
		Neighborhood:   req.Neighborhood,
		Street:         req.Street,
		Number:         req.Number,
		Complement:     req.Complement,
		PrimaryColor:   req.PrimaryColor,
		SecondaryColor: req.SecondaryColor,
		LogoURL:        req.LogoURL,
		AdminEmail:     req.Email,
		AdminPassword:  req.Password,
		AdminName:      req.FullName,
	}

	tenant, admin, err := h.agencyService.RegisterAgency(internalReq)
	if err != nil {
		log.Printf("❌ Error registering agency: %v", err)
		switch err {
		case service.ErrSubdomainTaken:
			http.Error(w, err.Error(), http.StatusConflict)
		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
	}

	log.Printf("✅ Agency created: %s (ID: %s)", tenant.Name, tenant.ID)

	// Generate JWT token for the new admin
	claims := jwt.MapClaims{
		"user_id":   admin.ID.String(),
		"email":     admin.Email,
		"role":      admin.Role,
		"tenant_id": tenant.ID.String(),
		"exp":       time.Now().Add(time.Hour * 24 * 7).Unix(), // 7 days
		"iat":       time.Now().Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString([]byte(h.cfg.JWT.Secret))
	if err != nil {
		http.Error(w, "Failed to generate token", http.StatusInternalServerError)
		return
	}

	protocol := "http://"
	if h.cfg.App.Environment == "production" {
		protocol = "https://"
	}

	response := map[string]interface{}{
		"token":      tokenString,
		"id":         admin.ID,
		"email":      admin.Email,
		"name":       admin.Name,
		"role":       admin.Role,
		"tenantId":   tenant.ID,
		"company":    tenant.Name,
		"subdomain":  tenant.Subdomain,
		"message":    "Agency registered successfully",
		"access_url": protocol + tenant.Domain,
	}

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

// RegisterClient handles client registration (ADMIN_AGENCIA only)
func (h *AgencyRegistrationHandler) RegisterClient(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// TODO: Get tenant_id from authenticated user context
	// For now, this would need the auth middleware to set it

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

	// Get tenantID from context (set by middleware)
	tenantIDStr := r.Header.Get("X-Tenant-ID")
	if tenantIDStr == "" {
		http.Error(w, "Tenant not found", http.StatusBadRequest)
		return
	}

	// Parse tenant ID
	// tenantID, _ := uuid.Parse(tenantIDStr)

	// client, err := h.agencyService.RegisterClient(req, tenantID)
	// ... handle response

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(map[string]string{
		"message": "Client registration endpoint - implementation pending",
	})
}

// HandleAgency supports GET (details) and DELETE operations for a specific agency
func (h *AgencyRegistrationHandler) HandleAgency(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/api/admin/agencies/" {
		http.Error(w, "Agency ID required", http.StatusBadRequest)
		return
	}

	vars := mux.Vars(r)
	agencyID := vars["id"]
	if agencyID == "" {
		http.Error(w, "Missing agency ID", http.StatusBadRequest)
		return
	}

	id, err := uuid.Parse(agencyID)
	if err != nil {
		http.Error(w, "Invalid agency ID", http.StatusBadRequest)
		return
	}

	switch r.Method {
	case http.MethodGet:
		details, err := h.agencyService.GetAgencyDetails(id)
		if err != nil {
			if errors.Is(err, service.ErrTenantNotFound) {
				http.Error(w, "Agency not found", http.StatusNotFound)
				return
			}
			http.Error(w, "Internal server error", http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(details)

	case http.MethodPatch:
		var updateData map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&updateData); err != nil {
			http.Error(w, "Invalid request body", http.StatusBadRequest)
			return
		}

		if isActive, ok := updateData["is_active"].(bool); ok {
			if err := h.agencyService.UpdateAgencyStatus(id, isActive); err != nil {
				if errors.Is(err, service.ErrTenantNotFound) {
					http.Error(w, "Agency not found", http.StatusNotFound)
					return
				}
				http.Error(w, "Internal server error", http.StatusInternalServerError)
				return
			}
		}

		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"message": "Status updated"})

	case http.MethodDelete:
		if err := h.agencyService.DeleteAgency(id); err != nil {
			if errors.Is(err, service.ErrTenantNotFound) {
				http.Error(w, "Agency not found", http.StatusNotFound)
				return
			}
			http.Error(w, "Internal server error", http.StatusInternalServerError)
			return
		}

		w.WriteHeader(http.StatusNoContent)

	default:
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
	}
}
