// Package main implements the ML TUI
package main

import (
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/jfraeys/fetch_ml/cmd/tui/internal/config"
	"github.com/jfraeys/fetch_ml/cmd/tui/internal/controller"
	"github.com/jfraeys/fetch_ml/cmd/tui/internal/model"
	"github.com/jfraeys/fetch_ml/cmd/tui/internal/services"
	"github.com/jfraeys/fetch_ml/cmd/tui/internal/view"
	"github.com/jfraeys/fetch_ml/internal/auth"
	"github.com/jfraeys/fetch_ml/internal/logging"
)

// AppModel represents the main application model for the TUI.
type AppModel struct {
	state      model.State
	controller *controller.Controller
}

// Init initializes the TUI application.
func (m AppModel) Init() tea.Cmd {
	return m.controller.Init()
}

// Update handles application updates and messages.
func (m AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	newState, cmd := m.controller.Update(msg, m.state)
	m.state = newState
	return m, cmd
}

// View renders the TUI interface.
func (m AppModel) View() string {
	return view.Render(m.state)
}

func main() {
	// Redirect logs to file to prevent TUI disruption
	homeDir, _ := os.UserHomeDir()
	logDir := filepath.Join(homeDir, ".ml", "logs")
	os.MkdirAll(logDir, 0755)
	logFile, logErr := os.OpenFile(filepath.Join(logDir, "tui.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if logErr == nil {
		log.SetOutput(logFile)
		defer logFile.Close()
	}

	// Parse authentication flags
	authFlags := auth.ParseAuthFlags()
	if err := auth.ValidateFlags(authFlags); err != nil {
		log.Fatalf("Authentication flag error: %v", err)
	}

	// Get API key from various sources
	apiKey := auth.GetAPIKeyFromSources(authFlags)

	var (
		cfg         *config.Config
		cliConfig   *config.CLIConfig
		cliConfPath string
	)

	configFlag := authFlags.ConfigFile

	// Only support TOML configuration
	var err error
	cliConfig, cliConfPath, err = config.LoadCLIConfig(configFlag)
	if err != nil {
		if configFlag != "" {
			log.Fatalf("Failed to load TOML config %s: %v", configFlag, err)
		}
		// Provide helpful error message for data scientists
		log.Printf("=== Fetch ML TUI - Configuration Required ===")
		log.Printf("")
		log.Printf("Error: %v", err)
		log.Printf("")
		log.Printf("To get started with the TUI, you need to initialize your configuration:")
		log.Printf("")
		log.Printf("Option 1: Using the Zig CLI (Recommended)")
		log.Printf("  1. Build the CLI: cd cli && make build")
		log.Printf("  2. Initialize config: ./cli/zig-out/bin/ml init")
		log.Printf("  3. Edit ~/.ml/config.toml with your settings")
		log.Printf("  4. Run TUI: ./bin/tui")
		log.Printf("")
		log.Printf("Option 2: Manual Configuration")
		log.Printf("  1. Create directory: mkdir -p ~/.ml")
		log.Printf("  2. Create config: touch ~/.ml/config.toml")
		log.Printf("  3. Add your settings to the file")
		log.Printf("  4. Run TUI: ./bin/tui")
		log.Printf("")
		log.Printf("Example ~/.ml/config.toml:")
		log.Printf("  mode = \"dev\"")
		log.Printf("  # Paths auto-resolve based on mode:")
		log.Printf("  # dev mode: ./data/dev/experiments")
		log.Printf("  # prod mode: ./data/prod/experiments")
		log.Printf("  api_key = \"your_api_key_here\"")
		log.Printf("")
		log.Printf("For more help, see: https://github.com/jfraeys/fetch_ml/docs")
		os.Exit(1)
	}

	cfg, err = cliConfig.ToTUIConfig()
	if err != nil {
		log.Fatalf("Failed to convert CLI config to TUI config: %v", err)
	}
	log.Printf("Loaded TOML configuration from %s", cliConfPath)

	// Force local mode - TUI runs on server with direct filesystem access
	cfg.Host = ""
	// Clear BasePath to force mode-based path resolution
	cfg.BasePath = ""

	// Validate authentication configuration
	if err := cfg.Auth.ValidateAuthConfig(); err != nil {
		log.Fatalf("Invalid authentication configuration: %v", err)
	}

	if err := cfg.Validate(); err != nil {
		log.Fatalf("Invalid configuration: %v", err)
	}

	// Test authentication if enabled
	if cfg.Auth.Enabled {
		// Use API key from CLI config if available, otherwise use from flags
		var effectiveAPIKey string
		switch {
		case cliConfig != nil && cliConfig.APIKey != "":
			effectiveAPIKey = cliConfig.APIKey
		case apiKey != "":
			effectiveAPIKey = apiKey
		default:
			log.Fatal("Authentication required but no API key provided")
		}

		if _, err := cfg.Auth.ValidateAPIKey(effectiveAPIKey); err != nil {
			log.Fatalf("Authentication failed: %v", err)
		}
	}

	srv, err := services.NewMLServer(cfg)
	if err != nil {
		log.Fatalf("Failed to initialize local server: %v", err)
	}
	defer func() {
		if err := srv.Close(); err != nil {
			log.Printf("server close error: %v", err)
		}
	}()

	// TaskQueue is optional for local mode
	tq, err := services.NewTaskQueue(cfg)
	if err != nil {
		log.Printf("Warning: Failed to connect to Redis: %v", err)
		log.Printf("Continuing without task queue functionality")
		tq = nil
	}
	if tq != nil {
		defer func() {
			if err := tq.Close(); err != nil {
				log.Printf("task queue close error: %v", err)
			}
		}()
	}

	// Initialize logger with file output only (prevents TUI disruption)
	logFilePath := filepath.Join(logDir, "tui.log")
	logger := logging.NewFileLogger(-4, false, logFilePath) // -4 = slog.LevelError

	// Initialize State and Controller
	var effectiveAPIKey string
	if cliConfig != nil && cliConfig.APIKey != "" {
		effectiveAPIKey = cliConfig.APIKey
	} else {
		effectiveAPIKey = apiKey
	}

	initialState := model.InitialState(effectiveAPIKey)
	ctrl := controller.New(cfg, srv, tq, logger)

	appModel := AppModel{
		state:      initialState,
		controller: ctrl,
	}

	// Run TUI program with graceful shutdown on SIGINT/SIGTERM
	p := tea.NewProgram(appModel, tea.WithAltScreen(), tea.WithMouseAllMotion())

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

	go func() {
		<-sigChan
		logger.Info("Received shutdown signal, closing TUI...")
		p.Quit()
	}()

	if _, err := p.Run(); err != nil {
		_ = p.ReleaseTerminal()
		logger.Error("Error running TUI", "error", err)
		return
	}

	// Ensure terminal is released and resources are closed via defer statements
	_ = p.ReleaseTerminal()
	logger.Info("TUI shutdown complete")
}
