// Package main provides the BugSETI system tray application.
// BugSETI - "Distributed Bug Fixing like SETI@home but for code"
//
// The application runs as a system tray app that:
// - Pulls OSS issues from GitHub
// - Uses AI to prepare context for each issue
// - Presents issues to users for fixing
// - Automates PR submission
package main

import (
	"embed"
	"io/fs"
	"log"
	"net/http"
	"runtime"
	"strings"

	"github.com/host-uk/core/cmd/bugseti/icons"
	"github.com/host-uk/core/internal/bugseti"
	"github.com/host-uk/core/internal/bugseti/updater"
	"github.com/wailsapp/wails/v3/pkg/application"
	"github.com/wailsapp/wails/v3/pkg/events"
)

//go:embed all:frontend/dist/bugseti/browser
var assets embed.FS

func main() {
	// Strip the embed path prefix so files are served from root
	staticAssets, err := fs.Sub(assets, "frontend/dist/bugseti/browser")
	if err != nil {
		log.Fatal(err)
	}

	// Initialize the config service
	configService := bugseti.NewConfigService()
	if err := configService.Load(); err != nil {
		log.Printf("Warning: Could not load config: %v", err)
	}

	// Initialize core services
	notifyService := bugseti.NewNotifyService(configService)
	statsService := bugseti.NewStatsService(configService)
	fetcherService := bugseti.NewFetcherService(configService, notifyService)
	queueService := bugseti.NewQueueService(configService)
	seederService := bugseti.NewSeederService(configService)
	submitService := bugseti.NewSubmitService(configService, notifyService, statsService)
	versionService := bugseti.NewVersionService()
	workspaceService := NewWorkspaceService(configService)

	// Initialize update service
	updateService, err := updater.NewService(configService)
	if err != nil {
		log.Printf("Warning: Could not initialize update service: %v", err)
	}

	// Create the tray service (we'll set the app reference later)
	trayService := NewTrayService(nil)

	// Build services list
	services := []application.Service{
		application.NewService(configService),
		application.NewService(notifyService),
		application.NewService(statsService),
		application.NewService(fetcherService),
		application.NewService(queueService),
		application.NewService(seederService),
		application.NewService(submitService),
		application.NewService(versionService),
		application.NewService(workspaceService),
		application.NewService(trayService),
	}

	// Add update service if available
	if updateService != nil {
		services = append(services, application.NewService(updateService))
	}

	// Create the application
	app := application.New(application.Options{
		Name:        "BugSETI",
		Description: "Distributed Bug Fixing - like SETI@home but for code",
		Services:    services,
		Assets: application.AssetOptions{
			Handler: spaHandler(staticAssets),
		},
		Mac: application.MacOptions{
			ActivationPolicy: application.ActivationPolicyAccessory,
		},
	})

	// Set the app reference and services in tray service
	trayService.app = app
	trayService.SetServices(fetcherService, queueService, configService, statsService)

	// Set up system tray
	setupSystemTray(app, fetcherService, queueService, configService)

	// Start update service background checker
	if updateService != nil {
		updateService.Start()
	}

	log.Println("Starting BugSETI...")
	log.Println("  - System tray active")
	log.Println("  - Waiting for issues...")
	log.Printf("  - Version: %s (%s)", bugseti.GetVersion(), bugseti.GetChannel())

	if err := app.Run(); err != nil {
		log.Fatal(err)
	}

	// Stop update service on exit
	if updateService != nil {
		updateService.Stop()
	}
}

// setupSystemTray configures the system tray icon and menu
func setupSystemTray(app *application.App, fetcher *bugseti.FetcherService, queue *bugseti.QueueService, config *bugseti.ConfigService) {
	systray := app.SystemTray.New()
	systray.SetTooltip("BugSETI - Distributed Bug Fixing")

	// Set tray icon based on OS
	if runtime.GOOS == "darwin" {
		systray.SetTemplateIcon(icons.TrayTemplate)
	} else {
		systray.SetDarkModeIcon(icons.TrayDark)
		systray.SetIcon(icons.TrayLight)
	}

	// Create tray panel window (workbench preview)
	trayWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
		Name:             "tray-panel",
		Title:            "BugSETI",
		Width:            420,
		Height:           520,
		URL:              "/tray",
		Hidden:           true,
		Frameless:        true,
		BackgroundColour: application.NewRGB(22, 27, 34),
	})
	systray.AttachWindow(trayWindow).WindowOffset(5)

	// Create main workbench window
	workbenchWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
		Name:             "workbench",
		Title:            "BugSETI Workbench",
		Width:            1200,
		Height:           800,
		URL:              "/workbench",
		Hidden:           true,
		BackgroundColour: application.NewRGB(22, 27, 34),
	})

	// Create settings window
	settingsWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
		Name:             "settings",
		Title:            "BugSETI Settings",
		Width:            600,
		Height:           500,
		URL:              "/settings",
		Hidden:           true,
		BackgroundColour: application.NewRGB(22, 27, 34),
	})

	// Create onboarding window
	onboardingWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
		Name:             "onboarding",
		Title:            "Welcome to BugSETI",
		Width:            700,
		Height:           600,
		URL:              "/onboarding",
		Hidden:           true,
		BackgroundColour: application.NewRGB(22, 27, 34),
	})

	// Build tray menu
	trayMenu := app.Menu.New()

	// Status item (dynamic)
	statusItem := trayMenu.Add("Status: Idle")
	statusItem.SetEnabled(false)

	trayMenu.AddSeparator()

	// Start/Pause toggle
	startPauseItem := trayMenu.Add("Start Fetching")
	startPauseItem.OnClick(func(ctx *application.Context) {
		if fetcher.IsRunning() {
			fetcher.Pause()
			startPauseItem.SetLabel("Start Fetching")
			statusItem.SetLabel("Status: Paused")
		} else {
			fetcher.Start()
			startPauseItem.SetLabel("Pause")
			statusItem.SetLabel("Status: Running")
		}
	})

	trayMenu.AddSeparator()

	// Current Issue
	currentIssueItem := trayMenu.Add("Current Issue: None")
	currentIssueItem.OnClick(func(ctx *application.Context) {
		if issue := queue.CurrentIssue(); issue != nil {
			workbenchWindow.Show()
			workbenchWindow.Focus()
		}
	})

	// Open Workbench
	trayMenu.Add("Open Workbench").OnClick(func(ctx *application.Context) {
		workbenchWindow.Show()
		workbenchWindow.Focus()
	})

	trayMenu.AddSeparator()

	// Settings
	trayMenu.Add("Settings...").OnClick(func(ctx *application.Context) {
		settingsWindow.Show()
		settingsWindow.Focus()
	})

	// Stats submenu
	statsMenu := trayMenu.AddSubmenu("Stats")
	statsMenu.Add("Issues Fixed: 0").SetEnabled(false)
	statsMenu.Add("PRs Merged: 0").SetEnabled(false)
	statsMenu.Add("Repos Contributed: 0").SetEnabled(false)

	trayMenu.AddSeparator()

	// Quit
	trayMenu.Add("Quit BugSETI").OnClick(func(ctx *application.Context) {
		app.Quit()
	})

	systray.SetMenu(trayMenu)

	// Check if onboarding needed (deferred until app is running)
	app.Event.RegisterApplicationEventHook(events.Common.ApplicationStarted, func(event *application.ApplicationEvent) {
		if !config.IsOnboarded() {
			onboardingWindow.Show()
			onboardingWindow.Focus()
		}
	})
}

// spaHandler wraps an fs.FS to serve static files with SPA fallback.
// If the requested path doesn't match a real file, it serves index.html
// so Angular's client-side router can handle the route.
func spaHandler(fsys fs.FS) http.Handler {
	fileServer := http.FileServer(http.FS(fsys))
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		path := strings.TrimPrefix(r.URL.Path, "/")
		if path == "" {
			path = "index.html"
		}

		// Check if the file exists
		if _, err := fs.Stat(fsys, path); err != nil {
			// File doesn't exist — serve index.html for SPA routing
			r.URL.Path = "/"
		}
		fileServer.ServeHTTP(w, r)
	})
}
