package main

import (
	"context"
	"database/sql"
	"log"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"deployment-manager/internal/api"
	"deployment-manager/internal/db"
	"deployment-manager/internal/events"
	"deployment-manager/internal/reconciler"
	"deployment-manager/internal/worker"

	_ "github.com/mattn/go-sqlite3"
)

const (
	dbPath        = "./manager.db"
	maxWorkers    = 2
	reconcileTick = 2 * time.Second
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// ---- graceful shutdown ----
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-sig
		log.Println("shutdown signal received")
		cancel()
	}()

	// ---- DB ----
	database, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		log.Fatal(err)
	}
	defer database.Close()

	if err := db.Migrate(database); err != nil {
		log.Fatal(err)
	}

	// ---- channels ----
	jobQueue := make(chan int64, 100)
	
	// ---- event bus ----
	eventBus := events.NewBus()
	
	// Subscribe to events for workers
	eventChan := eventBus.Subscribe(ctx)

	// ---- worker pool ----
	var wg sync.WaitGroup
	for i := 0; i < maxWorkers; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			w := worker.NewWorker(id, database, eventChan, jobQueue)
			w.Run(ctx)
		}(i)
	}

	// ---- reconciler ----
	reconciler := reconciler.NewReconciler(database, jobQueue, reconcileTick)
	go reconciler.Run(ctx)

	// ---- HTTP (API + SSE) ----
	httpServer := api.NewHTTPServer(database, eventBus)
	go func() {
		log.Println("HTTP server listening on :8080")
		if err := httpServer.Start(":8080"); err != nil && err != http.ErrServerClosed {
			log.Fatal(err)
		}
	}()

	<-ctx.Done()
	log.Println("shutting down...")

	httpServer.Shutdown(context.Background())
	close(jobQueue)
	wg.Wait()
	log.Println("bye")
}
