// Package main demonstrates MCA SDK usage for internal ML models in Go.
package main

import (
	"context"
	"fmt"
	"log"
	"math/rand"
	"sync"
	"time"

	mca "github.com/baptisthealth/mca-sdk-go"
	"github.com/baptisthealth/mca-sdk-go/config"
)

// simulatePrediction simulates a model prediction with random latency.
func simulatePrediction() (float64, string, error) {
	// Simulate processing time (50-200ms)
	latency := 0.05 + rand.Float64()*0.15
	time.Sleep(time.Duration(latency * float64(time.Second)))

	// Generate prediction ID
	predictionID := fmt.Sprintf("pred-%d", time.Now().UnixNano())

	return latency, predictionID, nil
}

func main() {
	// Initialize random seed
	rand.Seed(time.Now().UnixNano())

	// Create client configuration
	// This can also be loaded from environment variables with config.LoadFromEnv()
	cfg := &config.Config{
		ServiceName:       "readmission-model-go",
		ModelID:           "mdl-go-001",
		TeamName:          "clinical-ai",
		ModelVersion:      "2.0.0",
		ModelType:         "internal",
		ModelCategory:     "internal",
		CollectorEndpoint: "http://localhost:4318",
		Protocol:          "http",
		TLSInsecure:       true, // Allow insecure for local development
		DebugMode:         true,
	}

	// Initialize MCA client with timeout context
	log.Println("Initializing MCA SDK client...")
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	client, err := mca.NewClient(ctx, cfg)
	if err != nil {
		log.Fatalf("Failed to create MCA client: %v", err)
	}
	// Use defer to ensure graceful shutdown
	defer func() {
		log.Println("Shutting down MCA SDK client...")
		if err := client.Shutdown(); err != nil {
			log.Printf("Error during shutdown: %v", err)
		}
	}()

	log.Println("MCA SDK client initialized successfully")

	// Example 1: Single prediction
	log.Println("\n=== Example 1: Single Prediction ===")
	recordCtx := context.Background()
	latency, predID, err := simulatePrediction()
	if err != nil {
		log.Printf("Prediction failed: %v", err)
	} else {
		pred := &mca.Prediction{
			Latency:      &latency,
			PredictionID: predID,
			Attributes: map[string]string{
				"model_version": "2.0.0",
				"patient_age":   "65",
			},
		}
		if err := client.RecordPrediction(recordCtx, pred); err != nil {
			log.Printf("Failed to record prediction: %v", err)
		} else {
			log.Printf("Recorded prediction: ID=%s, Latency=%.3fs", predID, latency)
		}
	}

	// Example 2: Multiple predictions sequentially
	log.Println("\n=== Example 2: Multiple Sequential Predictions ===")
	for i := 0; i < 5; i++ {
		latency, predID, err := simulatePrediction()
		if err != nil {
			log.Printf("Prediction %d failed: %v", i+1, err)
			continue
		}
		pred := &mca.Prediction{
			Latency:      &latency,
			PredictionID: predID,
			Attributes: map[string]string{
				"model_version": "2.0.0",
				"batch_id":      fmt.Sprintf("batch-%d", i+1),
			},
		}
		if err := client.RecordPrediction(recordCtx, pred); err != nil {
			log.Printf("Failed to record prediction %d: %v", i+1, err)
		} else {
			log.Printf("Recorded prediction %d/%d: ID=%s, Latency=%.3fs", i+1, 5, predID, latency)
		}
	}

	// Example 3: Concurrent predictions (goroutine-safe)
	log.Println("\n=== Example 3: Concurrent Predictions ===")
	const numWorkers = 10
	const predictionsPerWorker = 5

	var wg sync.WaitGroup
	wg.Add(numWorkers)

	startTime := time.Now()
	for i := 0; i < numWorkers; i++ {
		go func(workerID int) {
			defer wg.Done()
			for j := 0; j < predictionsPerWorker; j++ {
				latency, predID, err := simulatePrediction()
				if err != nil {
					log.Printf("Worker %d prediction %d failed: %v", workerID, j+1, err)
					continue
				}
				pred := &mca.Prediction{
					Latency:      &latency,
					PredictionID: predID,
					Attributes: map[string]string{
						"model_version":  "2.0.0",
						"worker_id":      fmt.Sprintf("%d", workerID),
						"prediction_num": fmt.Sprintf("%d", j+1),
					},
				}
				if err := client.RecordPrediction(context.Background(), pred); err != nil {
					log.Printf("Worker %d failed to record prediction %d: %v", workerID, j+1, err)
				}
			}
		}(i)
	}

	wg.Wait()
	elapsed := time.Since(startTime)
	totalPredictions := numWorkers * predictionsPerWorker
	log.Printf("Completed %d concurrent predictions in %.2fs (%.0f predictions/sec)",
		totalPredictions, elapsed.Seconds(), float64(totalPredictions)/elapsed.Seconds())

	// Example 4: Context with timeout
	log.Println("\n=== Example 4: Prediction with Context Timeout ===")
	ctxWithTimeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	latency, predID, err = simulatePrediction()
	if err != nil {
		log.Printf("Prediction failed: %v", err)
	} else {
		pred := &mca.Prediction{
			Latency:      &latency,
			PredictionID: predID,
			Attributes: map[string]string{
				"model_version": "2.0.0",
				"timeout_demo":  "true",
			},
		}
		if err := client.RecordPrediction(ctxWithTimeout, pred); err != nil {
			log.Printf("Failed to record prediction: %v", err)
		} else {
			log.Printf("Recorded prediction with context: ID=%s, Latency=%.3fs", predID, latency)
		}
	}

	log.Println("\n=== All Examples Completed ===")
	log.Println("Telemetry data has been sent to OTel Collector at http://localhost:4318")
	log.Println("Check Prometheus metrics, Cloud Trace, and Cloud Logging for recorded data")
}
