package main

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
)

// GetAIModelsHandler returns all AI models
func (db *DB) GetAIModelsHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	ctx := context.Background()
	rows, err := db.pool.Query(ctx, `
		SELECT model_id, model_code, model_name, model_category, model_icon, model_color,
		       description, purpose, version, is_active, is_public, parameter_count,
		       health_score, status, last_health_check, created_at, updated_at
		FROM ic3_ai_models
		WHERE is_public = true
		ORDER BY model_code
	`)
	if err != nil {
		log.Printf("Query failed: %v", err)
		http.Error(w, "Query failed", http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var models []AIModel
	for rows.Next() {
		var m AIModel
		if err := rows.Scan(
			&m.ModelID, &m.ModelCode, &m.ModelName, &m.ModelCategory, &m.ModelIcon, &m.ModelColor,
			&m.Description, &m.Purpose, &m.Version, &m.IsActive, &m.IsPublic, &m.ParameterCount,
			&m.HealthScore, &m.Status, &m.LastHealthCheck, &m.CreatedAt, &m.UpdatedAt,
		); err != nil {
			log.Printf("Scan error: %v", err)
			continue
		}
		models = append(models, m)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(APIResponse{Success: true, Data: models})
}

// GetAIModelByCodeHandler returns a specific AI model with parameters and metrics
func (db *DB) GetAIModelByCodeHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	modelCode := r.URL.Query().Get("code")
	if modelCode == "" {
		http.Error(w, "Missing model code", http.StatusBadRequest)
		return
	}

	ctx := context.Background()

	// Get model
	var model AIModel
	err := db.pool.QueryRow(ctx, `
		SELECT model_id, model_code, model_name, model_category, model_icon, model_color,
		       description, purpose, version, is_active, is_public, parameter_count,
		       health_score, status, last_health_check, created_at, updated_at
		FROM ic3_ai_models
		WHERE model_code = $1
	`, modelCode).Scan(
		&model.ModelID, &model.ModelCode, &model.ModelName, &model.ModelCategory, &model.ModelIcon, &model.ModelColor,
		&model.Description, &model.Purpose, &model.Version, &model.IsActive, &model.IsPublic, &model.ParameterCount,
		&model.HealthScore, &model.Status, &model.LastHealthCheck, &model.CreatedAt, &model.UpdatedAt,
	)

	if err != nil {
		http.Error(w, "Model not found", http.StatusNotFound)
		return
	}

	// Get parameters
	paramRows, err := db.pool.Query(ctx, `
		SELECT param_id, param_code, param_name, param_description, data_type, unit,
		       source_sensor_type, sampling_rate_seconds, is_required, is_active
		FROM ic3_ai_model_parameters
		WHERE model_id = $1 AND is_active = true
		ORDER BY param_code
	`, model.ModelID)
	if err != nil {
		log.Printf("Parameter query failed: %v", err)
	}
	defer paramRows.Close()

	var parameters []AIModelParameter
	for paramRows.Next() {
		var p AIModelParameter
		p.ModelID = model.ModelID
		if err := paramRows.Scan(
			&p.ParamID, &p.ParamCode, &p.ParamName, &p.ParamDescription, &p.DataType, &p.Unit,
			&p.SourceSensorType, &p.SamplingRateSeconds, &p.IsRequired, &p.IsActive,
		); err != nil {
			log.Printf("Parameter scan error: %v", err)
			continue
		}
		parameters = append(parameters, p)
	}

	// Get latest metrics
	var metrics *AIModelMetric
	err = db.pool.QueryRow(ctx, `
		SELECT metric_id, model_id, metric_date, accuracy_score, precision_score, f1_score,
		       predictions_made, false_positives, avg_confidence, avg_inference_time_ms,
		       data_quality_score, created_at
		FROM ic3_ai_model_metrics
		WHERE model_id = $1
		ORDER BY metric_date DESC
		LIMIT 1
	`, model.ModelID).Scan(
		&metrics.MetricID, &metrics.ModelID, &metrics.MetricDate, &metrics.AccuracyScore,
		&metrics.PrecisionScore, &metrics.F1Score, &metrics.PredictionsMade, &metrics.FalsePositives,
		&metrics.AvgConfidence, &metrics.AvgInferenceTimeMS, &metrics.DataQualityScore, &metrics.CreatedAt,
	)
	if err != nil {
		log.Printf("Metrics query error: %v", err)
		metrics = nil
	}

	// Build response
	response := map[string]interface{}{
		"model":      model,
		"parameters": parameters,
		"metrics":    metrics,
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(APIResponse{Success: true, Data: response})
}

// GetAIModelMetricsHandler returns historical metrics for a model
func (db *DB) GetAIModelMetricsHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	modelCode := r.URL.Query().Get("code")
	limit := r.URL.Query().Get("limit")
	if limit == "" {
		limit = "30"
	}

	if modelCode == "" {
		http.Error(w, "Missing model code", http.StatusBadRequest)
		return
	}

	ctx := context.Background()

	// Get model ID
	var modelID string
	err := db.pool.QueryRow(ctx, `SELECT model_id FROM ic3_ai_models WHERE model_code = $1`, modelCode).Scan(&modelID)
	if err != nil {
		http.Error(w, "Model not found", http.StatusNotFound)
		return
	}

	// Get metrics
	rows, err := db.pool.Query(ctx, `
		SELECT metric_id, model_id, metric_date, accuracy_score, precision_score, f1_score,
		       predictions_made, false_positives, avg_confidence, avg_inference_time_ms,
		       data_quality_score, created_at
		FROM ic3_ai_model_metrics
		WHERE model_id = $1
		ORDER BY metric_date DESC
		LIMIT $2
	`, modelID, limit)
	if err != nil {
		log.Printf("Metrics query failed: %v", err)
		http.Error(w, "Query failed", http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var metrics []AIModelMetric
	for rows.Next() {
		var m AIModelMetric
		if err := rows.Scan(
			&m.MetricID, &m.ModelID, &m.MetricDate, &m.AccuracyScore, &m.PrecisionScore, &m.F1Score,
			&m.PredictionsMade, &m.FalsePositives, &m.AvgConfidence, &m.AvgInferenceTimeMS,
			&m.DataQualityScore, &m.CreatedAt,
		); err != nil {
			log.Printf("Scan error: %v", err)
			continue
		}
		metrics = append(metrics, m)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(APIResponse{Success: true, Data: metrics})
}

// GetAIModelPredictionsHandler returns recent predictions for a model
func (db *DB) GetAIModelPredictionsHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	modelCode := r.URL.Query().Get("code")
	limit := r.URL.Query().Get("limit")
	if limit == "" {
		limit = "20"
	}

	if modelCode == "" {
		http.Error(w, "Missing model code", http.StatusBadRequest)
		return
	}

	ctx := context.Background()

	// Get model ID
	var modelID string
	err := db.pool.QueryRow(ctx, `SELECT model_id FROM ic3_ai_models WHERE model_code = $1`, modelCode).Scan(&modelID)
	if err != nil {
		http.Error(w, "Model not found", http.StatusNotFound)
		return
	}

	// Get predictions
	rows, err := db.pool.Query(ctx, `
		SELECT prediction_id, model_id, asset_id, asset_name, prediction_type,
		       prediction_value, prediction_confidence, prediction_severity,
		       key_features, recommendation, is_correct, created_at
		FROM ic3_ai_predictions
		WHERE model_id = $1
		ORDER BY created_at DESC
		LIMIT $2
	`, modelID, limit)
	if err != nil {
		log.Printf("Predictions query failed: %v", err)
		http.Error(w, "Query failed", http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var predictions []AIPrediction
	for rows.Next() {
		var p AIPrediction
		if err := rows.Scan(
			&p.PredictionID, &p.ModelID, &p.AssetID, &p.AssetName, &p.PredictionType,
			&p.PredictionValue, &p.PredictionConfidence, &p.PredictionSeverity,
			&p.KeyFeatures, &p.Recommendation, &p.IsCorrect, &p.CreatedAt,
		); err != nil {
			log.Printf("Scan error: %v", err)
			continue
		}
		predictions = append(predictions, p)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(APIResponse{Success: true, Data: predictions})
}

// UpdateAIModelConfigHandler updates model configuration
func (db *DB) UpdateAIModelConfigHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

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

	ctx := context.Background()

	// Check if config exists
	var configID string
	err := db.pool.QueryRow(ctx, `
		SELECT config_id FROM ic3_ai_model_config
		WHERE model_id = $1 AND config_name = $2
	`, config.ModelID, config.ConfigName).Scan(&configID)

	if err == nil {
		// Update existing config
		_, err = db.pool.Exec(ctx, `
			UPDATE ic3_ai_model_config
			SET config_description = $1, threshold_values = $2,
			    feature_weights = $3, hyperparameters = $4, is_active = $5
			WHERE config_id = $6
		`, config.ConfigDescription, config.ThresholdValues, config.FeatureWeights,
			config.Hyperparameters, config.IsActive, configID)
	} else {
		// Create new config
		_, err = db.pool.Exec(ctx, `
			INSERT INTO ic3_ai_model_config
			(model_id, config_name, config_description, threshold_values, feature_weights, hyperparameters, is_active)
			VALUES ($1, $2, $3, $4, $5, $6, $7)
		`, config.ModelID, config.ConfigName, config.ConfigDescription, config.ThresholdValues,
			config.FeatureWeights, config.Hyperparameters, config.IsActive)
	}

	if err != nil {
		log.Printf("Config update failed: %v", err)
		http.Error(w, "Update failed", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(APIResponse{Success: true, Message: "Configuration updated successfully"})
}
