package main

import (
	"context"
	"database/sql"
	"embed"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"
)

//go:embed migrations/*.sql
var migrationsFS embed.FS

type Server struct {
	db        *sql.DB
	issuesDir string
	flowsDir  string
	hub       *SSEHub
}

func main() {
	port := flag.Int("port", 8487, "HTTP port")
	dbPath := flag.String("db", "operations.db", "SQLite path")
	registryRoot := flag.String("registry", "", "fn_registry root (default: auto-detect from cwd)")
	flag.Parse()

	root := *registryRoot
	if root == "" {
		root = detectRegistryRoot()
	}
	issuesDir := filepath.Join(root, "dev", "issues")
	flowsDir := filepath.Join(root, "dev", "flows")

	for _, d := range []string{issuesDir, flowsDir} {
		if _, err := os.Stat(d); err != nil {
			log.Fatalf("missing dir %s: %v", d, err)
		}
	}

	db, err := openDB(*dbPath)
	if err != nil {
		log.Fatalf("openDB: %v", err)
	}
	defer db.Close()
	if err := applyMigrations(db); err != nil {
		log.Fatalf("applyMigrations: %v", err)
	}

	srv := &Server{
		db:        db,
		issuesDir: issuesDir,
		flowsDir:  flowsDir,
		hub:       newSSEHub(),
	}

	if err := srv.ingestAll(); err != nil {
		log.Fatalf("initial ingest: %v", err)
	}

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

	go srv.watchLoop(ctx, srv.issuesDir, "issue")
	go srv.watchLoop(ctx, srv.flowsDir, "flow")

	mux := http.NewServeMux()
	srv.registerRoutes(mux)
	httpSrv := &http.Server{
		Addr:         fmt.Sprintf(":%d", *port),
		Handler:      withMiddleware(mux),
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 30 * time.Second,
	}

	go func() {
		log.Printf("kanban_cpp_backend listening on :%d (registry=%s)", *port, root)
		if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %v", err)
		}
	}()

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	<-sig
	log.Println("shutdown")
	shutdownCtx, cancelShutdown := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancelShutdown()
	httpSrv.Shutdown(shutdownCtx)
}

func detectRegistryRoot() string {
	wd, _ := os.Getwd()
	for d := wd; d != "/" && d != "."; d = filepath.Dir(d) {
		if _, err := os.Stat(filepath.Join(d, "registry.db")); err == nil {
			return d
		}
	}
	log.Fatalf("could not auto-detect fn_registry root from %s", wd)
	return ""
}
