package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net/http"
	"time"

	"github.com/redis/go-redis/v9"
)

// AssetHealthScore represents health assessment from ai_asset_health_score
type AssetHealthScore struct {
	HealthID              string    `json:"healthId"`
	AssetID               string    `json:"assetId"`
	ModelID               string    `json:"modelId"`
	HealthScore           float64   `json:"healthScore"`
	RiskLevel             string    `json:"riskLevel"`
	FailureProbability30d float64   `json:"failureProbability30d"`
	CalculatedTime        time.Time `json:"calculatedTime"`
}

// CMSWorkOrder represents a work order from cmms_work_order
type CMSWorkOrder struct {
	WorkOrderID   string    `json:"workOrderId"`
	AssetID       string    `json:"assetId"`
	DMAID         string    `json:"dmaId"`
	WOType        string    `json:"woType"`
	Priority      string    `json:"priority"`
	Status        string    `json:"status"`
	Description   string    `json:"description"`
	CreatedTime   time.Time `json:"createdTime"`
}

// ============================================================================
// Pump Health Worker
// ============================================================================

// RunPumpHealthWorker periodically calculates pump health scores
func RunPumpHealthWorker(ctx context.Context, db *DB, rdb *redis.Client) {
	ticker := time.NewTicker(1 * time.Hour)
	defer ticker.Stop()

	log.Println("Pump health worker started (1 hour interval)")

	// Run once immediately, then on ticker
	processPumpHealth(ctx, db, rdb)

	for {
		select {
		case <-ctx.Done():
			log.Println("Pump health worker stopped")
			return
		case <-ticker.C:
			processPumpHealth(ctx, db, rdb)
		}
	}
}

func processPumpHealth(ctx context.Context, db *DB, rdb *redis.Client) {
	ctx, cancel := context.WithTimeout(ctx, 55*time.Minute)
	defer cancel()

	// Query active pumps from asset master
	rows, err := db.pool.Query(ctx, `
		SELECT asset_id, install_date, design_life_years, dma_id
		FROM ic3_asset_master
		WHERE asset_type = 'PUMP'
		AND asset_status = 'ACTIVE'
	`)
	if err != nil {
		log.Printf("pump health query error: %v", err)
		return
	}
	defer rows.Close()

	for rows.Next() {
		var assetID, dmaID string
		var installDate *time.Time
		var designLifeYears *float64

		if err := rows.Scan(&assetID, &installDate, &designLifeYears, &dmaID); err != nil {
			log.Printf("pump health scan error: %v", err)
			continue
		}

		// Calculate age score
		var ageScore float64
		if installDate == nil {
			ageScore = 80.0
		} else {
			ageDays := time.Since(*installDate).Hours() / 24
			lifeDays := 365.0
			if designLifeYears != nil {
				lifeDays = *designLifeYears * 365.0
			}
			ageScore = math.Max(0, 100*(1-(ageDays/lifeDays)))
		}

		// Calculate health score: (condition*0.35) + (age*0.20) + 45.0
		// condition_score assumed to be 80 (can be enhanced later)
		conditionScore := 80.0
		healthScore := (conditionScore * 0.35) + (ageScore * 0.20) + 45.0
		healthScore = math.Max(0, math.Min(100, healthScore))

		// Determine risk level
		riskLevel := "CRITICAL"
		if healthScore >= 75 {
			riskLevel = "LOW"
		} else if healthScore >= 50 {
			riskLevel = "MEDIUM"
		} else if healthScore >= 25 {
			riskLevel = "HIGH"
		}

		// Calculate failure probability
		failureProb := (100 - healthScore) / 100

		// Insert into ai_asset_health_score
		var healthID string
		err := db.pool.QueryRow(ctx, `
			INSERT INTO ai_asset_health_score (
				asset_id, model_id, health_score, risk_level,
				failure_probability_30d, calculated_time
			) VALUES ($1, $2, $3, $4, $5, $6)
			RETURNING health_id
		`,
			assetID, "pump-v5", healthScore, riskLevel, failureProb, time.Now(),
		).Scan(&healthID)

		if err != nil {
			log.Printf("insert health score error: %v", err)
			continue
		}

		// If failure probability > 0.40, check for open work orders
		if failureProb > 0.40 {
			var existingWO int
			err := db.pool.QueryRow(ctx, `
				SELECT COUNT(*) FROM cmms_work_order
				WHERE asset_id = $1
				AND status IN ('OPEN', 'IN_PROGRESS')
			`, assetID).Scan(&existingWO)

			if err == nil && existingWO == 0 {
				// No open work order, create one
				year := time.Now().Year()
				// Use asset_id hash for sequence (simplified approach)
				seq := int(healthID[0]) % 1000000

				woID := fmt.Sprintf("WO-%d-%06d", year, seq)

				_, err := db.pool.Exec(ctx, `
					INSERT INTO cmms_work_order (
						work_order_id, asset_id, dma_id, wo_type,
						priority, status, description, created_time
					) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
				`,
					woID, assetID, dmaID, "PREVENTIVE_MAINTENANCE",
					"HIGH", "OPEN",
					fmt.Sprintf("Preventive maintenance: pump health score %.2f%%, failure probability %.2f%%",
						healthScore, failureProb*100),
					time.Now(),
				)
				if err != nil {
					log.Printf("insert work order error: %v", err)
				}
			}
		}

		// Cache to Redis for 1 hour
		healthData := map[string]interface{}{
			"health_id":               healthID,
			"asset_id":                assetID,
			"health_score":            healthScore,
			"risk_level":              riskLevel,
			"failure_probability_30d": failureProb,
			"calculated_time":         time.Now(),
		}
		healthJSON, _ := json.Marshal(healthData)
		rdb.Set(ctx, fmt.Sprintf("health:asset:%s", assetID), string(healthJSON), 1*time.Hour)
	}
}

// ============================================================================
// HTTP Handlers
// ============================================================================

// GET /api/v1/health/assets
func getAssetsHealthHandler(db *DB, rdb *redis.Client) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
		defer cancel()

		// Get latest health scores per asset
		rows, err := db.pool.Query(ctx, `
			SELECT DISTINCT ON (asset_id)
				health_id, asset_id, model_id, health_score, risk_level,
				failure_probability_30d, calculated_time
			FROM ai_asset_health_score
			ORDER BY asset_id, calculated_time DESC
		`)
		if err != nil {
			w.WriteHeader(500)
			json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
			return
		}
		defer rows.Close()

		var healthScores []AssetHealthScore
		for rows.Next() {
			var h AssetHealthScore
			err := rows.Scan(
				&h.HealthID, &h.AssetID, &h.ModelID, &h.HealthScore,
				&h.RiskLevel, &h.FailureProbability30d, &h.CalculatedTime,
			)
			if err != nil {
				continue
			}
			healthScores = append(healthScores, h)
		}

		if healthScores == nil {
			healthScores = []AssetHealthScore{}
		}

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

// GET /api/v1/health/asset/{id}
func getAssetHealthHandler(db *DB, rdb *redis.Client) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		assetID := r.PathValue("id")
		if assetID == "" {
			w.WriteHeader(400)
			json.NewEncoder(w).Encode(map[string]string{"error": "asset_id required"})
			return
		}

		ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
		defer cancel()

		// Try Redis first
		val, err := rdb.Get(ctx, fmt.Sprintf("health:asset:%s", assetID)).Result()
		if err == nil {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(200)
			fmt.Fprint(w, val)
			return
		}

		// Fall back to database
		var h AssetHealthScore
		err = db.pool.QueryRow(ctx, `
			SELECT health_id, asset_id, model_id, health_score, risk_level,
				failure_probability_30d, calculated_time
			FROM ai_asset_health_score
			WHERE asset_id = $1
			ORDER BY calculated_time DESC
			LIMIT 1
		`, assetID).Scan(
			&h.HealthID, &h.AssetID, &h.ModelID, &h.HealthScore,
			&h.RiskLevel, &h.FailureProbability30d, &h.CalculatedTime,
		)

		if err != nil {
			w.WriteHeader(404)
			json.NewEncoder(w).Encode(map[string]string{"error": "asset health not found"})
			return
		}

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