package main

import (
	"context"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// runDaemon mantiene call_monitor vivo como systemd service. Cada `interval`
// ejecuta los pasos batch en orden (snapshot + sequences --detect --propose).
// Idempotente: cada uno se salta trabajo ya hecho. Errores se loguean y no
// abortan el daemon (siguiente tick lo reintenta).
func runDaemon(dbPath, registryRoot string, interval time.Duration) {
	log.Printf("call_monitor daemon: db=%s registry=%s interval=%s",
		dbPath, registryRoot, interval)

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

	// Signal handling — clean exit on SIGTERM/SIGINT.
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		s := <-sigCh
		log.Printf("call_monitor daemon: received %s, shutting down", s)
		cancel()
	}()

	// Initial cycle immediately, then on interval.
	runCycleSafe(dbPath, registryRoot)

	tick := time.NewTicker(interval)
	defer tick.Stop()

	for {
		select {
		case <-ctx.Done():
			log.Printf("call_monitor daemon: stopped")
			return
		case <-tick.C:
			runCycleSafe(dbPath, registryRoot)
		}
	}
}

func runCycleSafe(dbPath, registryRoot string) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("call_monitor daemon: cycle panic recovered: %v", r)
		}
	}()

	// Snapshot: registra (function_id, content_hash) en function_versions.
	log.Printf("call_monitor daemon: cycle start")
	runSnapshot(dbPath, registryRoot)

	// Sequences detection: persiste candidatas + proposals new_pipeline.
	cfg := SequenceConfig{
		WindowSecs:     30,
		LookbackDays:   30,
		MinOccurrences: 5,
		MinSessions:    2,
		MinSuccessRate: 0.9,
	}
	runSequences(dbPath, true, false, true, false, registryRoot, cfg)

	log.Printf("call_monitor daemon: cycle done")
}
