package handlers

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"

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

	"github.com/google/uuid"
	"github.com/gorilla/mux"
)

// PlanHandler handles plan-related endpoints
type PlanHandler struct {
	planService *service.PlanService
}

// NewPlanHandler creates a new plan handler
func NewPlanHandler(planService *service.PlanService) *PlanHandler {
	return &PlanHandler{
		planService: planService,
	}
}

// RegisterRoutes registers plan routes
func (h *PlanHandler) RegisterRoutes(r *mux.Router) {
	// Note: Route protection is done in main.go with authMiddleware wrapper
	r.HandleFunc("/api/admin/plans", h.CreatePlan).Methods(http.MethodPost)
	r.HandleFunc("/api/admin/plans", h.ListPlans).Methods(http.MethodGet)
	r.HandleFunc("/api/admin/plans/{id}", h.GetPlan).Methods(http.MethodGet)
	r.HandleFunc("/api/admin/plans/{id}", h.UpdatePlan).Methods(http.MethodPut)
	r.HandleFunc("/api/admin/plans/{id}", h.DeletePlan).Methods(http.MethodDelete)

	// Public routes (for signup flow)
	r.HandleFunc("/api/plans", h.ListActivePlans).Methods(http.MethodGet)
	r.HandleFunc("/api/plans/{id}", h.GetActivePlan).Methods(http.MethodGet)
}

// CreatePlan creates a new plan (admin only)
func (h *PlanHandler) CreatePlan(w http.ResponseWriter, r *http.Request) {
	log.Printf("📋 CREATE PLAN - Method: %s", r.Method)

	var req domain.CreatePlanRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		log.Printf("❌ Invalid request body: %v", err)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]string{"error": "Invalid request body", "message": err.Error()})
		return
	}

	plan, err := h.planService.CreatePlan(&req)
	if err != nil {
		log.Printf("❌ Error creating plan: %v", err)
		w.Header().Set("Content-Type", "application/json")
		switch err {
		case service.ErrPlanSlugTaken:
			w.WriteHeader(http.StatusConflict)
			json.NewEncoder(w).Encode(map[string]string{"error": "Slug already taken", "message": err.Error()})
		case service.ErrInvalidUserRange:
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(map[string]string{"error": "Invalid user range", "message": err.Error()})
		default:
			w.WriteHeader(http.StatusInternalServerError)
			json.NewEncoder(w).Encode(map[string]string{"error": "Internal server error", "message": err.Error()})
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message": "Plan created successfully",
		"plan":    plan,
	})
	log.Printf("✅ Plan created: %s", plan.ID)
}

// GetPlan retrieves a plan by ID (admin only)
func (h *PlanHandler) GetPlan(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	idStr := vars["id"]

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

	plan, err := h.planService.GetPlan(id)
	if err != nil {
		if err == service.ErrPlanNotFound {
			http.Error(w, "Plan not found", http.StatusNotFound)
		} else {
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"plan": plan,
	})
}

// ListPlans retrieves all plans (admin only)
func (h *PlanHandler) ListPlans(w http.ResponseWriter, r *http.Request) {
	plans, err := h.planService.ListPlans()
	if err != nil {
		log.Printf("❌ Error listing plans: %v", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"plans": plans,
	})
	log.Printf("✅ Listed %d plans", len(plans))
}

// ListActivePlans retrieves all active plans (public)
func (h *PlanHandler) ListActivePlans(w http.ResponseWriter, r *http.Request) {
	plans, err := h.planService.ListActivePlans()
	if err != nil {
		log.Printf("❌ Error listing active plans: %v", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"plans": plans,
	})
}

// GetActivePlan retrieves an active plan by ID (public)
func (h *PlanHandler) GetActivePlan(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	idStr := vars["id"]

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

	plan, err := h.planService.GetPlan(id)
	if err != nil {
		if err == service.ErrPlanNotFound {
			http.Error(w, "Plan not found", http.StatusNotFound)
		} else {
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	// Check if plan is active
	if !plan.IsActive {
		http.Error(w, "Plan not available", http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"plan": plan,
	})
}

// UpdatePlan updates a plan (admin only)
func (h *PlanHandler) UpdatePlan(w http.ResponseWriter, r *http.Request) {
	log.Printf("📋 UPDATE PLAN - Method: %s", r.Method)

	vars := mux.Vars(r)
	idStr := vars["id"]

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

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

	plan, err := h.planService.UpdatePlan(id, &req)
	if err != nil {
		log.Printf("❌ Error updating plan: %v", err)
		switch err {
		case service.ErrPlanNotFound:
			http.Error(w, "Plan not found", http.StatusNotFound)
		case service.ErrPlanSlugTaken:
			http.Error(w, err.Error(), http.StatusConflict)
		case service.ErrInvalidUserRange:
			http.Error(w, err.Error(), http.StatusBadRequest)
		default:
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message": "Plan updated successfully",
		"plan":    plan,
	})
	log.Printf("✅ Plan updated: %s", plan.ID)
}

// DeletePlan deletes a plan (admin only)
func (h *PlanHandler) DeletePlan(w http.ResponseWriter, r *http.Request) {
	log.Printf("📋 DELETE PLAN - Method: %s", r.Method)

	vars := mux.Vars(r)
	idStr := vars["id"]

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

	err = h.planService.DeletePlan(id)
	if err != nil {
		log.Printf("❌ Error deleting plan: %v", err)
		switch err {
		case service.ErrPlanNotFound:
			http.Error(w, "Plan not found", http.StatusNotFound)
		default:
			http.Error(w, "Internal server error", http.StatusInternalServerError)
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message": "Plan deleted successfully",
	})
	log.Printf("✅ Plan deleted: %s", idStr)
}

// GetPlanByUserCount returns a plan for a given user count
func (h *PlanHandler) GetPlanByUserCount(w http.ResponseWriter, r *http.Request) {
	userCountStr := r.URL.Query().Get("user_count")
	if userCountStr == "" {
		http.Error(w, "user_count parameter required", http.StatusBadRequest)
		return
	}

	userCount, err := strconv.Atoi(userCountStr)
	if err != nil {
		http.Error(w, "Invalid user_count", http.StatusBadRequest)
		return
	}

	plan, err := h.planService.GetPlanByUserCount(userCount)
	if err != nil {
		http.Error(w, "No plan available for this user count", http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"plan": plan,
	})
}
