package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/services/cost/services"
)

// GetVinCost returns cost data for a specific VIN
// GET /cost/vin/{vin}?from=2024-01-01&to=2024-01-31
func GetVinCost(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Extract VIN from path
	path := strings.TrimPrefix(r.URL.Path, "/cost/vin/")
	vin := strings.TrimSuffix(path, "/")
	if vin == "" {
		http.Error(w, "VIN required", http.StatusBadRequest)
		return
	}

	from, to := parseTimeRange(r)

	summary, err := services.GetVinCostSummary(vin, from, to)
	if err != nil {
		logger.Error().Err(err).Str("vin", vin).Msg("Failed to get VIN cost")
		http.Error(w, "Failed to get cost data", http.StatusInternalServerError)
		return
	}

	respondJSON(w, summary)
}

// GetFleetCost returns fleet-wide cost summary
// GET /cost/fleet?from=2024-01-01&to=2024-01-31&limit=10
func GetFleetCost(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	from, to := parseTimeRange(r)
	limit := 10
	if l := r.URL.Query().Get("limit"); l != "" {
		if parsed, err := strconv.Atoi(l); err == nil {
			limit = parsed
		}
	}

	summary, err := services.GetFleetCostSummary(from, to, limit)
	if err != nil {
		logger.Error().Err(err).Msg("Failed to get fleet cost")
		http.Error(w, "Failed to get cost data", http.StatusInternalServerError)
		return
	}

	respondJSON(w, summary)
}

// GetCostSummary returns a high-level cost summary
// GET /cost/summary?period=day|week|month
func GetCostSummary(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	period := r.URL.Query().Get("period")
	if period == "" {
		period = "day"
	}

	to := time.Now()
	var from time.Time
	switch period {
	case "week":
		from = to.AddDate(0, 0, -7)
	case "month":
		from = to.AddDate(0, -1, 0)
	default:
		from = to.AddDate(0, 0, -1)
	}

	summary, err := services.GetFleetCostSummary(from, to, 5)
	if err != nil {
		logger.Error().Err(err).Msg("Failed to get cost summary")
		http.Error(w, "Failed to get cost data", http.StatusInternalServerError)
		return
	}

	respondJSON(w, map[string]interface{}{
		"period":          period,
		"summary":         summary,
		"cost_rates": map[string]interface{}{
			"cloud": map[string]float64{
				"cpu_per_core_hour":   services.CloudCPUPerCoreHour,
				"memory_per_gb_hour":  services.CloudMemoryPerGBHour,
			},
			"onprem": map[string]float64{
				"cpu_per_core_hour":   services.OnpremCPUPerCoreHour,
				"memory_per_gb_hour":  services.OnpremMemoryPerGBHour,
			},
		},
	})
}

// GetCostComparison returns cloud vs on-prem cost comparison
// GET /cost/comparison?from=2024-01-01&to=2024-01-31
func GetCostComparison(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	from, to := parseTimeRange(r)

	summary, err := services.GetFleetCostSummary(from, to, 0)
	if err != nil {
		logger.Error().Err(err).Msg("Failed to get cost comparison")
		http.Error(w, "Failed to get cost data", http.StatusInternalServerError)
		return
	}

	comparison := map[string]interface{}{
		"period": map[string]interface{}{
			"from": from,
			"to":   to,
		},
		"cloud": map[string]interface{}{
			"total_cost_usd":     summary.TotalCloudCost,
			"cost_per_vehicle":   0.0,
			"description":        "Azure cloud hosting with managed services",
		},
		"onprem": map[string]interface{}{
			"total_cost_usd":     summary.TotalOnpremCost,
			"cost_per_vehicle":   0.0,
			"description":        "Self-hosted on owned hardware (amortized)",
		},
		"savings": map[string]interface{}{
			"total_usd":    summary.TotalSavings,
			"percent":      summary.SavingsPercent,
			"annual_projected": summary.TotalSavings * 12,
		},
		"vehicle_count": summary.VehicleCount,
	}

	if summary.VehicleCount > 0 {
		comparison["cloud"].(map[string]interface{})["cost_per_vehicle"] = summary.TotalCloudCost / float64(summary.VehicleCount)
		comparison["onprem"].(map[string]interface{})["cost_per_vehicle"] = summary.TotalOnpremCost / float64(summary.VehicleCount)
	}

	respondJSON(w, comparison)
}

func parseTimeRange(r *http.Request) (from, to time.Time) {
	to = time.Now()
	from = to.AddDate(0, 0, -30) // Default to last 30 days

	if fromStr := r.URL.Query().Get("from"); fromStr != "" {
		if parsed, err := time.Parse("2006-01-02", fromStr); err == nil {
			from = parsed
		}
	}

	if toStr := r.URL.Query().Get("to"); toStr != "" {
		if parsed, err := time.Parse("2006-01-02", toStr); err == nil {
			to = parsed
		}
	}

	return
}

func respondJSON(w http.ResponseWriter, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(data); err != nil {
		logger.Error().Err(err).Msg("Failed to encode JSON response")
	}
}

// GetReport returns a plain text cost report
// GET /cost/report
func GetReport(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	to := time.Now()
	from := to.AddDate(0, -1, 0) // Last month

	summary, err := services.GetFleetCostSummary(from, to, 10)
	if err != nil {
		logger.Error().Err(err).Msg("Failed to get report data")
		http.Error(w, "Failed to get report data", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/plain")

	report := `
╔══════════════════════════════════════════════════════════════════╗
║                    COST SERVICE REPORT                           ║
╠══════════════════════════════════════════════════════════════════╣
║  Period: %s to %s
╠══════════════════════════════════════════════════════════════════╣
║  FLEET OVERVIEW                                                  ║
║  ─────────────────────────────────────────────────────────────── ║
║  Active Vehicles:     %d                                         
║  Cloud Cost:          $%.2f                                      
║  On-Prem Cost:        $%.2f                                      
║  Savings:             $%.2f (%.1f%%)                             
╠══════════════════════════════════════════════════════════════════╣
║  RESOURCE USAGE MODEL                                            ║
║  ─────────────────────────────────────────────────────────────── ║
║  Platform Base:       %.0f cores / %.0f GB RAM (fixed)           
║  Per-VIN Marginal:    %.0f millicores / %.0f MB RAM              
║  Total Fleet:         %.1f cores / %.1f GB RAM                   
╠══════════════════════════════════════════════════════════════════╣
║  COST FORMULA                                                    ║
║  ─────────────────────────────────────────────────────────────── ║
║  (Platform Base) + (Per-VIN × %d VINs) + Managed Services        
╠══════════════════════════════════════════════════════════════════╣
║  COST RATES                                                      ║
║  ─────────────────────────────────────────────────────────────── ║
║  Cloud:   CPU $%.2f/core-hr   Memory $%.3f/GB-hr                 
║  On-Prem: CPU $%.2f/core-hr   Memory $%.3f/GB-hr                 
║  Base Infra: Cloud $%.2f/15min   On-Prem $%.2f/15min             
╠══════════════════════════════════════════════════════════════════╣
║  ANNUAL PROJECTION (based on current usage)                      ║
║  ─────────────────────────────────────────────────────────────── ║
║  Cloud Annual:        $%.2f                                      
║  On-Prem Annual:      $%.2f                                      
║  Annual Savings:      $%.2f                                      
╚══════════════════════════════════════════════════════════════════╝
`
	annualCloud := summary.TotalCloudCost * 12
	annualOnprem := summary.TotalOnpremCost * 12
	annualSavings := annualCloud - annualOnprem

	// Calculate total fleet resources
	totalCPU := services.PlatformBaseCPUCores + (services.PerVinCPUCores * float64(summary.VehicleCount))
	totalRAM := services.PlatformBaseMemoryGB + (services.PerVinMemoryGB * float64(summary.VehicleCount))

	fmt.Fprintf(w, report,
		from.Format("2006-01-02"), to.Format("2006-01-02"),
		summary.VehicleCount,
		summary.TotalCloudCost,
		summary.TotalOnpremCost,
		summary.TotalSavings, summary.SavingsPercent,
		services.PlatformBaseCPUCores, services.PlatformBaseMemoryGB,
		services.PerVinCPUCores*1000, services.PerVinMemoryGB*1024,
		totalCPU, totalRAM,
		summary.VehicleCount,
		services.CloudCPUPerCoreHour, services.CloudMemoryPerGBHour,
		services.OnpremCPUPerCoreHour, services.OnpremMemoryPerGBHour,
		services.BaseInfraCloudCost, services.BaseInfraOnpremCost,
		annualCloud, annualOnprem, annualSavings,
	)

	// Add top cost VINs if any
	if len(summary.TopCostVins) > 0 {
		fmt.Fprintf(w, "\nTOP COST VEHICLES:\n")
		fmt.Fprintf(w, "%-20s %10s %10s %12s %12s %10s\n", "VIN", "CPU (mc)", "RAM (MB)", "Cloud $", "On-Prem $", "Savings %")
		fmt.Fprintf(w, "%-20s %10s %10s %12s %12s %10s\n", "───────────────────", "────────", "────────", "──────────", "──────────", "────────")
		for _, v := range summary.TopCostVins {
			fmt.Fprintf(w, "%-20s %10.0f %10.0f %12.2f %12.2f %9.1f%%\n",
				truncateVIN(v.VIN), v.AvgCPUCores*1000, v.AvgMemoryGB*1024, v.TotalCloudCost, v.TotalOnpremCost, v.SavingsPercent)
		}
	}
}

func truncateVIN(vin string) string {
	if len(vin) > 20 {
		return vin[:17] + "..."
	}
	return vin
}
