package main

import (
	"context"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/chorus-services/whoosh/internal/config"
	"github.com/chorus-services/whoosh/internal/database"
	"github.com/chorus-services/whoosh/internal/server"
	"github.com/chorus-services/whoosh/internal/tracing"
	"github.com/kelseyhightower/envconfig"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

const (
	serviceName = "whoosh"
)

var (
	// Build-time variables (set via ldflags)
	version    = "0.1.7"
	commitHash = "unknown"
	buildDate  = "unknown"
)

func main() {
	// Parse command line flags
	var (
		healthCheck = flag.Bool("health-check", false, "Run health check and exit")
		showVersion = flag.Bool("version", false, "Show version information and exit")
	)
	flag.Parse()

	// Handle version flag
	if *showVersion {
		fmt.Printf("WHOOSH %s\n", version)
		fmt.Printf("Commit: %s\n", commitHash)
		fmt.Printf("Built: %s\n", buildDate)
		return
	}

	// Handle health check flag
	if *healthCheck {
		if err := runHealthCheck(); err != nil {
			log.Fatal().Err(err).Msg("Health check failed")
		}
		return
	}

	// Configure structured logging
	setupLogging()

	log.Info().
		Str("service", serviceName).
		Str("version", version).
		Str("commit", commitHash).
		Str("build_date", buildDate).
		Msg("🎭 Starting WHOOSH - Autonomous AI Development Teams")

	// Load configuration
	var cfg config.Config

	// Debug: Print all environment variables starting with WHOOSH
	log.Debug().Msg("Environment variables:")
	for _, env := range os.Environ() {
		if strings.HasPrefix(env, "WHOOSH_") {
			// Don't log passwords in full, just indicate they exist
			if strings.Contains(env, "PASSWORD") {
				parts := strings.SplitN(env, "=", 2)
				if len(parts) == 2 && len(parts[1]) > 0 {
					log.Debug().Str("env", parts[0]+"=[REDACTED]").Msg("Found password env var")
				}
			} else {
				log.Debug().Str("env", env).Msg("Found env var")
			}
		}
	}

	if err := envconfig.Process("whoosh", &cfg); err != nil {
		log.Fatal().Err(err).Msg("Failed to load configuration")
	}

	// Validate configuration
	if err := cfg.Validate(); err != nil {
		log.Fatal().Err(err).Msg("Invalid configuration")
	}

	log.Info().
		Str("listen_addr", cfg.Server.ListenAddr).
		Str("database_host", cfg.Database.Host).
		Msg("📋 Configuration loaded")

	// Initialize database
	db, err := database.NewPostgresDB(cfg.Database)
	if err != nil {
		log.Fatal().Err(err).Msg("Failed to initialize database")
	}
	defer db.Close()

	log.Info().Msg("🗄️ Database connection established")

	// Run migrations
	if cfg.Database.AutoMigrate {
		log.Info().Msg("🔄 Running database migrations...")
		if err := database.RunMigrations(cfg.Database.URL); err != nil {
			log.Fatal().Err(err).Msg("Database migration failed")
		}
		log.Info().Msg("✅ Database migrations completed")
	}

	// Initialize tracing
	tracingCleanup, err := tracing.Initialize(cfg.OpenTelemetry)
	if err != nil {
		log.Fatal().Err(err).Msg("Failed to initialize tracing")
	}
	defer tracingCleanup()

	if cfg.OpenTelemetry.Enabled {
		log.Info().
			Str("jaeger_endpoint", cfg.OpenTelemetry.JaegerEndpoint).
			Msg("🔍 OpenTelemetry tracing enabled")
	} else {
		log.Info().Msg("🔍 OpenTelemetry tracing disabled (no-op tracer)")
	}

	// Set version for server
	server.SetVersion(version)

	// Initialize server
	srv, err := server.NewServer(&cfg, db)
	if err != nil {
		log.Fatal().Err(err).Msg("Failed to create server")
	}

	// Start server
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		log.Info().
			Str("addr", cfg.Server.ListenAddr).
			Msg("🌐 Starting HTTP server")

		if err := srv.Start(ctx); err != nil {
			log.Error().Err(err).Msg("Server startup failed")
			cancel()
		}
	}()

	// Wait for shutdown signal
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	select {
	case sig := <-sigChan:
		log.Info().Str("signal", sig.String()).Msg("🛑 Shutdown signal received")
	case <-ctx.Done():
		log.Info().Msg("🛑 Context cancelled")
	}

	// Graceful shutdown
	log.Info().Msg("🔄 Starting graceful shutdown...")

	shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer shutdownCancel()

	if err := srv.Shutdown(shutdownCtx); err != nil {
		log.Error().Err(err).Msg("Server shutdown failed")
	}

	log.Info().Msg("✅ WHOOSH shutdown complete")
}

func runHealthCheck() error {
	// Simple health check - try to connect to health endpoint
	client := &http.Client{Timeout: 5 * time.Second}

	// Use localhost for health check
	healthURL := "http://localhost:8080/health"

	resp, err := client.Get(healthURL)
	if err != nil {
		return fmt.Errorf("health check request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("health check returned status %d", resp.StatusCode)
	}

	return nil
}

func setupLogging() {
	// Configure zerolog for structured logging
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

	// Set log level from environment
	level := os.Getenv("LOG_LEVEL")
	switch level {
	case "debug":
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	case "info":
		zerolog.SetGlobalLevel(zerolog.InfoLevel)
	case "warn":
		zerolog.SetGlobalLevel(zerolog.WarnLevel)
	case "error":
		zerolog.SetGlobalLevel(zerolog.ErrorLevel)
	default:
		zerolog.SetGlobalLevel(zerolog.InfoLevel)
	}

	// Pretty logging for development
	if os.Getenv("ENVIRONMENT") == "development" {
		log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
	}
}
