package services

import (
	"time"

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

// Cost rates per hour
const (
	// Cloud costs (based on ~$1M/year = ~$83k/month Azure spend)
	// Includes: AKS compute, Event Hubs (Kafka), CosmosDB, Azure DB for PostgreSQL,
	// Azure Cache for Redis, Blob Storage, networking, monitoring, support
	CloudCPUPerCoreHour   = 0.35  // $/core/hour (Azure D-series + managed services + support)
	CloudMemoryPerGBHour  = 0.10  // $/GB/hour (includes managed DB, Redis, caching layers)

	// On-prem/bare metal costs (amortized hardware only)
	// Based on migration plan: 6 VMs, 80 cores, 544GB RAM, 17TB storage
	// Assumes: 3-year hardware amortization, minimal ops overhead
	// Does NOT include: datacenter, power, cooling, staff, network
	OnpremCPUPerCoreHour  = 0.015 // $/core/hour (~95% cheaper than cloud)
	OnpremMemoryPerGBHour = 0.004 // $/GB/hour

	// Per-VIN resource usage (marginal cost per vehicle)
	// This is the incremental CPU/RAM needed for each additional connected vehicle
	// Covers: telemetry ingestion, Kafka processing, storage writes, API queries
	PerVinCPUCores  = 0.05  // 50 millicores per VIN (marginal)
	PerVinMemoryGB  = 0.08  // 80MB per VIN (marginal)

	// Platform base resources (fixed cost regardless of VIN count)
	// Based on migration plan production environment:
	// VM1-4: 64GB RAM, 16 cores (Kafka, OTA, Valet, Auth/APIs)
	// VM5-6: 512GB RAM, 64 cores (ClickHouse, Analytics, Vehicle Data)
	// Total: 80 cores, 544GB RAM
	PlatformBaseCPUCores  = 80.0   // 80 cores for base platform (from migration plan)
	PlatformBaseMemoryGB  = 544.0  // 544GB RAM for base platform (from migration plan)

	// Base infrastructure cost per collection interval (managed services, storage, networking)
	// Cloud: Event Hubs, CosmosDB, Azure Storage, Defender, monitoring (~$50k/month of $83k total)
	// On-prem: ~90% cheaper - just hardware amortization + minimal hosting
	BaseInfraCloudCost  = 17.00 // $/15min for managed services (cloud) - ~$50k/month
	BaseInfraOnpremCost = 1.50  // $/15min for equivalent on-prem (~91% cheaper)
)

// CalculateCosts computes cloud and on-prem costs for given resource usage
func CalculateCosts(cpuCores, memoryGB float64, durationHours float64) (cloudCost, onpremCost float64) {
	cloudCost = (cpuCores * CloudCPUPerCoreHour * durationHours) +
		(memoryGB * CloudMemoryPerGBHour * durationHours)

	onpremCost = (cpuCores * OnpremCPUPerCoreHour * durationHours) +
		(memoryGB * OnpremMemoryPerGBHour * durationHours)

	return
}

// CalculatePlatformBaseCosts returns the fixed platform infrastructure costs
// This is the cost to run the platform regardless of VIN count
func CalculatePlatformBaseCosts(durationHours float64) (cloudCost, onpremCost float64) {
	cloudCost = (PlatformBaseCPUCores * CloudCPUPerCoreHour * durationHours) +
		(PlatformBaseMemoryGB * CloudMemoryPerGBHour * durationHours)

	onpremCost = (PlatformBaseCPUCores * OnpremCPUPerCoreHour * durationHours) +
		(PlatformBaseMemoryGB * OnpremMemoryPerGBHour * durationHours)

	return
}

// CalculatePerVinCosts returns the marginal cost for a single VIN
func CalculatePerVinCosts(durationHours float64, activityMultiplier float64) (cpuCores, memoryGB, cloudCost, onpremCost float64) {
	cpuCores = PerVinCPUCores * activityMultiplier
	memoryGB = PerVinMemoryGB * activityMultiplier
	cloudCost, onpremCost = CalculateCosts(cpuCores, memoryGB, durationHours)
	return
}

// CalculateBaseCosts returns the shared infrastructure costs for a collection interval
func CalculateBaseCosts() (cloudCost, onpremCost float64) {
	return BaseInfraCloudCost, BaseInfraOnpremCost
}

// StartMetricsCollector runs the background metrics collection loop
func StartMetricsCollector(interval time.Duration) {
	logger.Info().Msgf("Starting metrics collector with %v interval", interval)

	// Initial collection
	collectMetrics()

	ticker := time.NewTicker(interval)
	for range ticker.C {
		collectMetrics()
	}
}

func collectMetrics() {
	logger.Debug().Msg("Collecting metrics from remote ClickHouse")

	to := time.Now()
	from := to.Add(-15 * time.Minute) // Last 15 minutes

	// Get active VINs from remote clickhouse
	activeVins, err := FetchActiveVins(from, to)
	if err != nil {
		logger.Error().Err(err).Msg("Failed to fetch active VINs from remote ClickHouse")
		return
	}

	if len(activeVins) == 0 {
		logger.Debug().Msg("No active VINs found")
		return
	}

	durationHours := 0.25 // 15 minutes = 0.25 hours
	records := make([]CostRecord, 0, len(activeVins))

	// Calculate platform base costs (distributed across all VINs for reporting)
	platformCloudCost, platformOnpremCost := CalculatePlatformBaseCosts(durationHours)
	platformCloudPerVin := platformCloudCost / float64(len(activeVins))
	platformOnpremPerVin := platformOnpremCost / float64(len(activeVins))

	// Get managed services base costs (also distributed)
	baseCloud, baseOnprem := CalculateBaseCosts()
	baseCloudPerVin := baseCloud / float64(len(activeVins))
	baseOnpremPerVin := baseOnprem / float64(len(activeVins))

	for _, v := range activeVins {
		// Scale resource estimate by activity level
		activityMultiplier := 1.0
		if v.MessageCount > 1000 {
			activityMultiplier = 2.0
		} else if v.MessageCount > 100 {
			activityMultiplier = 1.5
		}

		// Calculate per-VIN marginal costs
		cpuCores, memoryGB, vinCloudCost, vinOnpremCost := CalculatePerVinCosts(durationHours, activityMultiplier)

		// Total cost = per-VIN marginal + share of platform base + share of managed services
		totalCloudCost := vinCloudCost + platformCloudPerVin + baseCloudPerVin
		totalOnpremCost := vinOnpremCost + platformOnpremPerVin + baseOnpremPerVin

		records = append(records, CostRecord{
			VIN:           v.VIN,
			Timestamp:     to,
			CPUCores:      cpuCores,
			MemoryGB:      memoryGB,
			CloudCostUSD:  totalCloudCost,
			OnpremCostUSD: totalOnpremCost,
			PodCount:      1,
		})
	}

	// Store in local ClickHouse
	if err := InsertCostRecords(records); err != nil {
		logger.Error().Err(err).Msg("Failed to insert cost records")
		return
	}

	logger.Info().Msgf("Collected and stored cost metrics for %d VINs (platform base: cloud $%.2f, on-prem $%.2f)", 
		len(records), platformCloudCost, platformOnpremCost)
}
