#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""Orchestrator Schedulers: Periodic batch jobs for PULSE brain maintenance."""
import logging
import threading
import time
from pathlib import Path

from pulse.daemons.orchestrator.scheduler_ops import scheduler_loop

log = logging.getLogger("pulse.daemons.orchestrator.schedulers")

SCRIPT_DIR = Path(__file__).resolve().parent
DAEMONS_DIR = SCRIPT_DIR.parent
ROOT_DIR = DAEMONS_DIR.parent.parent
OVERRIDE_FILE = ROOT_DIR / "state" / "homeostatic_overrides.json"

# --- Scheduler Intervals ---
DEDUP_INTERVAL = 6 * 3600
SYNTHESIZE_INTERVAL = 12 * 3600
PRUNE_INTERVAL = 24 * 3600
AUTO_CAPTURE_INTERVAL = 1 * 3600
ANTI_PATTERN_INTERVAL = 6 * 3600
PRIVATE_SYNTHESIS_INTERVAL = 24 * 3600
PREDICTION_INTERVAL = 5 * 60
BRAIN_HEALER_INTERVAL = 4 * 3600
PROFILE_DISTILLER_INTERVAL = 12 * 3600
CONSTRAINT_ENGINE_INTERVAL = 6 * 3600
GATE_FEEDBACK_DECAY_INTERVAL = 4 * 3600
PATHWEAVER_INTERVAL = 12 * 3600
CAUSAL_RECOVERY_INTERVAL = 30 * 60
SWARM_REFLEX_INTERVAL = 5 * 60
EPISTEMIC_FORAGER_INTERVAL = 24 * 3600
SKILL_SYNTHESIZER_INTERVAL = 24 * 3600
GHOST_RESONANCE_INTERVAL = 1 * 3600
HEBBIAN_BALANCER_INTERVAL = 15 * 60
SCHEMA_DAEMON_INTERVAL = 12 * 3600
PROCEDURE_DAEMON_INTERVAL = 12 * 3600
INTENT_DAEMON_INTERVAL = 12 * 3600
SLEEP_CYCLE_INTERVAL = 24 * 3600
GC_DAEMON_INTERVAL = 6 * 3600
MEMORY_DISPATCHER_INTERVAL = 1 * 3600
EMBEDDING_POPULATOR_INTERVAL = 1 * 3600
RECONSOLIDATION_DAEMON_INTERVAL = 1 * 3600
CULTURE_SYNTH_INTERVAL = 7 * 24 * 3600
PROJECT_MAP_INTERVAL = 24 * 3600

# --- Script Paths ---
DEDUP_SCRIPT = DAEMONS_DIR / "synthesis" / "core" / "pulse_dedup.py"
CONSOLIDATION_SCRIPT = DAEMONS_DIR / "consolidation" / "consolidation_daemon.py"
SYNTHESIZE_SCRIPT = DAEMONS_DIR / "synthesis" / "planning" / "synthesize_plans.py"
PRUNE_SCRIPT = ROOT_DIR / "pulse" / "admin" / "brain_ops" / "pulse_prune.py"
AUTO_CAPTURE_SCRIPT = ROOT_DIR / "pulse" / "brain" / "capture" / "auto_capture.py"
ANTI_PATTERN_SCRIPT = ROOT_DIR / "pulse" / "admin" / "patterns" / "anti_pattern_builder.py"
PRIVATE_SYNTHESIS_SCRIPT = ROOT_DIR / "pulse" / "admin" / "brain_ops" / "private_synthesis.py"
PREDICTION_DAEMON = DAEMONS_DIR / "neural" / "prediction_daemon.py"
BRAIN_HEALER_DAEMON = DAEMONS_DIR / "synthesis" / "core" / "brain_healer.py"
PROFILE_DISTILLER_DAEMON = DAEMONS_DIR / "synthesis" / "core" / "profile_distiller.py"
CONSTRAINT_ENGINE_DAEMON = DAEMONS_DIR / "synthesis" / "planning" / "constraint_engine.py"
GATE_FEEDBACK_DAEMON = DAEMONS_DIR / "neural" / "gate_feedback.py"
PATHWEAVER_DAEMON = DAEMONS_DIR / "synthesis" / "pathweaver" / "pathweaver.py"
CAUSAL_RECOVERY_DAEMON = DAEMONS_DIR / "synthesis" / "core" / "causal_claim_recovery.py"
SWARM_REFLEX_DAEMON = DAEMONS_DIR / "synthesis" / "swarm" / "swarm_reflex.py"
EPISTEMIC_FORAGER_DAEMON = DAEMONS_DIR / "synthesis" / "core" / "epistemic_forager.py"
SKILL_SYNTHESIZER_DAEMON = DAEMONS_DIR / "synthesis" / "skill" / "skill_dependency_synthesizer.py"
GHOST_RESONANCE_DAEMON = DAEMONS_DIR / "synthesis" / "resonance" / "ghost_resonance.py"
HEBBIAN_BALANCER_DAEMON = DAEMONS_DIR / "synthesis" / "learning" / "hebbian_balancer.py"
HOMEOSTATIC_DAEMON = DAEMONS_DIR / "synthesis" / "health" / "homeostatic_scheduler.py"
PIPELINE_HEALTH_SCRIPT = DAEMONS_DIR / "runtime" / "daemon_heartbeat.py"
HEALER_DAEMON = DAEMONS_DIR / "synthesis" / "sleep" / "procedural_sleep_healer.py"
PHYLOGENY_DAEMON = DAEMONS_DIR / "synthesis" / "skill" / "skill_phylogeny.py"
AGENT_PROC_SYNTH_DAEMON = DAEMONS_DIR / "synthesis" / "core" / "agent_procedure_synthesizer.py"
CHOREOGRAPHER_DAEMON = DAEMONS_DIR / "synthesis" / "swarm" / "swarm_choreographer.py"
COGNITIVE_HUD_DAEMON = DAEMONS_DIR / "neural" / "cognitive_hud.py"
ECHOREFINE_DAEMON = DAEMONS_DIR / "synthesis" / "resonance" / "echo_refine.py"
IMMUNITY_DAEMON = DAEMONS_DIR / "synthesis" / "swarm" / "swarm_immunity.py"
NEUROPLASTICITY_DAEMON = DAEMONS_DIR / "synthesis" / "learning" / "neuroplasticity.py"
RESONANCE_DAEMON = DAEMONS_DIR / "synthesis" / "resonance" / "prediction_resonance.py"
CONTENTION_CORTEX_DAEMON = DAEMONS_DIR / "synthesis" / "health" / "contention_cortex.py"
SKILL_RESONANCE_DAEMON = DAEMONS_DIR / "synthesis" / "skill" / "skill_resonance.py"
INTENT_TOPOLOGY_DAEMON = DAEMONS_DIR / "neural" / "intent_topology.py"
JIT_INOCULATION_DAEMON = DAEMONS_DIR / "synthesis" / "health" / "jit_inoculation.py"
COGNITIVE_TRIAGE_DAEMON = DAEMONS_DIR / "synthesis" / "health" / "cognitive_triage.py"
SCHEMA_DAEMON_SCRIPT = DAEMONS_DIR / "synthesis" / "core" / "schema_daemon.py"
PROCEDURE_DAEMON_SCRIPT = DAEMONS_DIR / "synthesis" / "core" / "procedure_daemon.py"
INTENT_DAEMON_SCRIPT = DAEMONS_DIR / "bridge" / "intent_daemon.py"
SLEEP_CYCLE_SCRIPT = DAEMONS_DIR / "synthesis" / "sleep" / "sleep_cycle.py"
GC_DAEMON_SCRIPT = DAEMONS_DIR / "runtime" / "gc_daemon.py"
MEMORY_DISPATCHER_SCRIPT = DAEMONS_DIR / "bridge" / "memory_dispatcher.py"
RETRIEVAL_SCHEDULER_SCRIPT = DAEMONS_DIR / "consolidation" / "retrieval_scheduler.py"
CONFLICT_MONITOR_SCRIPT = DAEMONS_DIR / "synthesis" / "core" / "conflict_monitor.py"
EMBEDDING_POPULATOR_SCRIPT = ROOT_DIR / "pulse" / "brain" / "index" / "embedding_populator.py"
ASSOCIATIVE_REPLAY_SCRIPT = DAEMONS_DIR / "synthesis" / "learning" / "associative_replay.py"
RECONSOLIDATION_DAEMON_SCRIPT = DAEMONS_DIR / "synthesis" / "learning" / "reconsolidation_daemon.py"
CULTURE_SYNTH_SCRIPT = DAEMONS_DIR / "consolidation" / "culture_synth.py"
PROJECT_MAP_SCRIPT = ROOT_DIR / "pulse" / "admin" / "brain_ops" / "project_map.py"


def start_all_schedulers(running_check):
    """Start all periodic batch job schedulers."""
    def s(script, label, interval, name, delay=0, timeout=120, args=None, boot=True):
        scheduler_loop(script, label, interval, running_check, name, delay, timeout, args, boot, OVERRIDE_FILE)

    script = CONSOLIDATION_SCRIPT if CONSOLIDATION_SCRIPT.exists() else DEDUP_SCRIPT
    s(script, "Consolidation", DEDUP_INTERVAL, "consolidation_scheduler", timeout=600)
    s(SYNTHESIZE_SCRIPT, "Synthesize", SYNTHESIZE_INTERVAL, "synthesize_scheduler")
    s(PRUNE_SCRIPT, "Prune", PRUNE_INTERVAL, "prune_scheduler")
    s(AUTO_CAPTURE_SCRIPT, "Auto-capture", AUTO_CAPTURE_INTERVAL, "auto_capture_scheduler", args=["--batch"])
    s(ANTI_PATTERN_SCRIPT, "Anti-pattern builder", ANTI_PATTERN_INTERVAL, "anti_pattern_scheduler", delay=30)
    s(PRIVATE_SYNTHESIS_SCRIPT, "Private synthesis", PRIVATE_SYNTHESIS_INTERVAL, "private_synthesis_scheduler")
    s(PREDICTION_DAEMON, "Prediction", PREDICTION_INTERVAL, "prediction_scheduler", delay=60, timeout=60, args=["--once"])
    s(BRAIN_HEALER_DAEMON, "Brain Healer", BRAIN_HEALER_INTERVAL, "brain_healer_scheduler", delay=120, timeout=300)
    s(PROFILE_DISTILLER_DAEMON, "Profile Distiller", PROFILE_DISTILLER_INTERVAL, "profile_distiller_scheduler", delay=180, timeout=300, boot=False)
    s(CONSTRAINT_ENGINE_DAEMON, "Constraint Engine", CONSTRAINT_ENGINE_INTERVAL, "constraint_engine_scheduler", delay=240, timeout=300, args=["--once"], boot=False)
    s(GATE_FEEDBACK_DAEMON, "Gate Feedback Decay", GATE_FEEDBACK_DECAY_INTERVAL, "gate_feedback_scheduler", delay=60, timeout=60, args=["--decay"])
    s(PATHWEAVER_DAEMON, "Pathweaver", PATHWEAVER_INTERVAL, "pathweaver_scheduler", delay=300, timeout=300, args=["--once"])
    s(CAUSAL_RECOVERY_DAEMON, "Causal Recovery", CAUSAL_RECOVERY_INTERVAL, "causal_recovery_scheduler", delay=60, timeout=120, args=["--once"], boot=False)
    s(SWARM_REFLEX_DAEMON, "Swarm Reflex", SWARM_REFLEX_INTERVAL, "swarm_reflex_scheduler", delay=90, timeout=60, args=["--once"])
    s(SCHEMA_DAEMON_SCRIPT, "Schema Daemon", SCHEMA_DAEMON_INTERVAL, "schema_daemon_scheduler", delay=360, timeout=300, args=["--once", "--verbose"], boot=False)
    s(PROCEDURE_DAEMON_SCRIPT, "Procedure Daemon", PROCEDURE_DAEMON_INTERVAL, "procedure_daemon_scheduler", delay=420, timeout=300, args=["--once", "--verbose"], boot=False)
    s(INTENT_DAEMON_SCRIPT, "Intent Daemon", INTENT_DAEMON_INTERVAL, "intent_daemon_scheduler", delay=480, timeout=300, args=["--once", "--verbose"], boot=False)
    s(SLEEP_CYCLE_SCRIPT, "Sleep Cycle", SLEEP_CYCLE_INTERVAL, "sleep_cycle_scheduler", delay=600, timeout=600, args=["--verbose"], boot=False)
    s(EPISTEMIC_FORAGER_DAEMON, "Epistemic Forager", EPISTEMIC_FORAGER_INTERVAL, "epistemic_forager_scheduler", delay=660, timeout=300, args=["--once"], boot=False)
    s(SKILL_SYNTHESIZER_DAEMON, "Skill Synthesizer", SKILL_SYNTHESIZER_INTERVAL, "skill_synthesizer_scheduler", delay=720, timeout=300, args=["--once"], boot=False)
    s(GHOST_RESONANCE_DAEMON, "Ghost Resonance", GHOST_RESONANCE_INTERVAL, "ghost_resonance_scheduler", delay=180, timeout=120, boot=False)
    s(HEBBIAN_BALANCER_DAEMON, "Hebbian Balancer", HEBBIAN_BALANCER_INTERVAL, "hebbian_balancer_scheduler", delay=120, timeout=60, boot=False)
    s(HOMEOSTATIC_DAEMON, "Homeostatic Scheduler", 60, "homeostatic_scheduler", delay=180, timeout=30, args=["--once"], boot=False)
    s(HEALER_DAEMON, "Procedural Sleep Healer", 12 * 3600, "healer_scheduler", delay=540, timeout=120, args=["--once"], boot=False)
    s(PHYLOGENY_DAEMON, "Phylogenetic Compiler", 12 * 3600, "phylogeny_scheduler", delay=780, timeout=300, args=["--once", "-v"], boot=False)
    s(AGENT_PROC_SYNTH_DAEMON, "Agent Procedure Synth", 24 * 3600, "agent_proc_synth_scheduler", delay=840, timeout=300, args=["--once", "-v"], boot=False)
    s(PIPELINE_HEALTH_SCRIPT, "Pipeline Health", 60, "pipeline_health_scheduler", delay=30, timeout=30, args=["--once", "--verbose"])
    s(CHOREOGRAPHER_DAEMON, "Swarm Choreographer", 10 * 60, "choreographer_scheduler", delay=300, timeout=60, boot=False)
    s(COGNITIVE_HUD_DAEMON, "Cognitive HUD", 60, "cognitive_hud_scheduler", delay=120, timeout=30, args=["--once"], boot=False)
    s(ECHOREFINE_DAEMON, "EchoRefine Synthesis", 6 * 3600, "echorefine_scheduler", delay=900, timeout=120, boot=False)
    s(IMMUNITY_DAEMON, "Swarm Immunity", 5 * 60, "immunity_scheduler", delay=120, timeout=60)
    s(NEUROPLASTICITY_DAEMON, "Neuroplasticity", 30 * 60, "neuroplasticity_scheduler", delay=600, timeout=120, boot=False)
    s(RESONANCE_DAEMON, "Prediction Resonance", 30 * 60, "resonance_scheduler", delay=660, timeout=120, boot=False)
    s(CONTENTION_CORTEX_DAEMON, "Contention Cortex", 15 * 60, "contention_cortex_scheduler", delay=360, timeout=120, boot=False)
    s(SKILL_RESONANCE_DAEMON, "Skill Resonance", 15 * 60, "skill_resonance_scheduler", delay=420, timeout=60, boot=False)
    s(INTENT_TOPOLOGY_DAEMON, "Intent Topology", 30 * 60, "intent_topology_scheduler", delay=480, timeout=120, boot=False)
    s(JIT_INOCULATION_DAEMON, "JIT Inoculation", 2 * 60, "jit_inoculation_scheduler", delay=60, timeout=30)
    s(COGNITIVE_TRIAGE_DAEMON, "Cognitive Triage", 60, "cognitive_triage_scheduler", delay=30, timeout=30)
    s(GC_DAEMON_SCRIPT, "GC Daemon", 6 * 3600, "gc_daemon_scheduler", delay=300, timeout=120, boot=False)
    s(MEMORY_DISPATCHER_SCRIPT, "Memory Dispatcher", MEMORY_DISPATCHER_INTERVAL, "memory_dispatcher_scheduler", delay=300, timeout=120, boot=False)
    s(RETRIEVAL_SCHEDULER_SCRIPT, "Retrieval Scheduler", 6 * 3600, "retrieval_scheduler", delay=90, timeout=120)
    s(CONFLICT_MONITOR_SCRIPT, "Conflict Monitor", 3600, "conflict_monitor_scheduler", delay=150, timeout=120, boot=False)
    s(EMBEDDING_POPULATOR_SCRIPT, "Embedding Populator", EMBEDDING_POPULATOR_INTERVAL, "embedding_populator_scheduler", delay=10, timeout=600, args=["--batch-size", "200"])
    s(ASSOCIATIVE_REPLAY_SCRIPT, "Associative Replay", 12 * 3600, "associative_replay_scheduler", delay=600, timeout=300, args=["--once"], boot=False)
    s(RECONSOLIDATION_DAEMON_SCRIPT, "Reconsolidation Daemon", RECONSOLIDATION_DAEMON_INTERVAL, "reconsolidation_daemon_scheduler", delay=120, timeout=120, args=["--once"])
    s(CULTURE_SYNTH_SCRIPT, "Culture Synthesis", CULTURE_SYNTH_INTERVAL, "culture_synth_scheduler", delay=3600, timeout=300, boot=True)
    s(PROJECT_MAP_SCRIPT, "Project Map Refresh", PROJECT_MAP_INTERVAL, "project_map_scheduler", delay=60, timeout=60)

    def _reconsolidation_sweep_loop():
        while running_check():
            try:
                from pulse.brain.plasticity.reconsolidation import _sweep_expired
                _sweep_expired()
            except Exception: pass
            time.sleep(60)
    threading.Thread(target=_reconsolidation_sweep_loop, daemon=True, name="recon_sweep").start()

    def _micro_consolidation_loop():
        time.sleep(30)
        while running_check():
            try:
                from pulse.daemons.consolidation.micro_consolidation import run_micro_cycle
                run_micro_cycle(verbose=False)
            except Exception: pass
            time.sleep(60)
    threading.Thread(target=_micro_consolidation_loop, daemon=True, name="micro_consolidation").start()
