import dotenv from 'dotenv';
dotenv.config({ path: require('path').resolve(__dirname, '../../.env') });

import { query } from '../db';
import { alerter } from '../services/alerter';

// Phase 2 tasks
import { runWatchdog } from './tasks/watchdog';
import { runSchemaGuard } from './tasks/schema-guard';

// Phase 3 tasks
import { runCLVTracker } from './tasks/clv-tracker';
import { runEdgeDecay } from './tasks/edge-decay';

// Phase 4 tasks
import { runMovementClassifier } from './tasks/movement-classifier';
import { runOpportunityScanner } from './tasks/opportunity-scanner';
import { updateBookProfiles } from './tasks/book-profiler';

// Phase 5 tasks
import { updateRiskState } from './tasks/risk-manager';

// Phase 6 tasks
import { sendDailyBrief } from './tasks/daily-brief';
import { runNightlySim } from './tasks/nightly-simulator';
import { runSelfImprover } from './tasks/self-improver';
import { logMissedEdges } from './tasks/missed-edge-logger';
import { runFalsePositiveTracker } from './tasks/false-positive-tracker';

// ---

type GlobalMode = 'normal' | 'cautious' | 'defensive' | 'frozen';

interface TaskDef {
  fn: () => Promise<void>;
  interval?: string;    // e.g. '10m', '2h', '6h'
  cron?: string;        // cron expression
  activeHoursOnly?: boolean;
  requiresMode?: GlobalMode[];  // only run if mode is one of these
  heavy?: boolean;      // serialized with other heavy tasks
}

const SCHEDULE: Record<string, TaskDef> = {
  // Phase 2: Resilience
  watchdog:           { interval: '10m',  fn: runWatchdog },
  healthCheck:        { interval: '2h',   fn: async () => {
    const { systemMonitor } = await import('../services/system-monitor');
    await systemMonitor.updateGlobalState();
  }},
  schemaGuard:        { interval: '30m',  fn: runSchemaGuard },

  // Phase 3: Edge Measurement
  clvTracker:         { interval: '2h',   fn: runCLVTracker, heavy: true },
  edgeDecayCheck:     { interval: '6h',   fn: runEdgeDecay },

  // Phase 4: Intelligence
  movementClassifier: { interval: '5m',   fn: runMovementClassifier },
  opportunityScanner: { interval: '10m',  fn: runOpportunityScanner, requiresMode: ['normal'] },
  bookProfileUpdate:  { interval: '6h',   fn: updateBookProfiles, heavy: true },

  // Phase 5: Risk
  riskStateUpdate:    { interval: '1h',   fn: updateRiskState },

  // Phase 6: Autonomy
  dailyBrief:         { cron: '0 13 * * *',  fn: sendDailyBrief },       // 8 AM ET
  nightlySimulation:  { cron: '0 7 * * *',   fn: runNightlySim, heavy: true },  // 2 AM ET
  selfImprover:       { cron: '0 8 * * 0',   fn: runSelfImprover },      // Sun 3 AM ET
  missedEdgeLogger:   { cron: '0 14 * * *',  fn: logMissedEdges },       // 9 AM ET
  falsePositives:     { cron: '0 15 * * *',  fn: runFalsePositiveTracker }, // 10 AM ET
};

// --- Scheduler Engine ---

const runningTasks = new Set<string>();
let heavyLock = false;

function parseInterval(interval: string): number {
  const match = interval.match(/^(\d+)(m|h)$/);
  if (!match) throw new Error(`Invalid interval: ${interval}`);
  const [, num, unit] = match;
  return parseInt(num) * (unit === 'h' ? 3600000 : 60000);
}

function isActiveHours(): boolean {
  const now = new Date();
  const etHour = parseInt(now.toLocaleString('en-US', { timeZone: 'America/New_York', hour: 'numeric', hour12: false }));
  return etHour >= 10 && etHour < 24;
}

function matchesCron(cronExpr: string): boolean {
  const now = new Date();
  const utcMin = now.getUTCMinutes();
  const utcHour = now.getUTCHours();
  const utcDow = now.getUTCDay();

  const parts = cronExpr.split(' ');
  if (parts.length !== 5) return false;

  const [cronMin, cronHour, , , cronDow] = parts;

  if (cronMin !== '*' && parseInt(cronMin) !== utcMin) return false;
  if (cronHour !== '*' && parseInt(cronHour) !== utcHour) return false;
  if (cronDow !== '*' && parseInt(cronDow) !== utcDow) return false;

  return true;
}

async function getGlobalMode(): Promise<GlobalMode> {
  try {
    const result = await query(`SELECT mode FROM sc_global_state WHERE id = 'primary'`);
    return (result.rows[0]?.mode as GlobalMode) || 'normal';
  } catch {
    return 'normal';
  }
}

async function runTask(name: string, taskDef: TaskDef): Promise<void> {
  if (runningTasks.has(name)) return; // prevent overlap

  // Check active hours
  if (taskDef.activeHoursOnly && !isActiveHours()) return;

  // Check mode requirements
  if (taskDef.requiresMode) {
    const mode = await getGlobalMode();
    if (!taskDef.requiresMode.includes(mode)) return;
  }

  // Check heavy lock
  if (taskDef.heavy && heavyLock) return;

  runningTasks.add(name);
  if (taskDef.heavy) heavyLock = true;

  const startTime = Date.now();
  try {
    await taskDef.fn();
  } catch (error) {
    const duration = Date.now() - startTime;
    const errMsg = error instanceof Error ? error.message : String(error);
    console.error(`[orchestrator] Task ${name} failed:`, errMsg);

    await alerter.logEvent(
      'task_failure',
      'warn',
      name,
      `Task ${name} failed after ${duration}ms: ${errMsg}`,
      { error: errMsg, duration_ms: duration }
    );
  } finally {
    runningTasks.delete(name);
    if (taskDef.heavy) heavyLock = false;
  }
}

// --- Main Loop ---

async function main() {
  console.log('[sc-orchestrator] Starting SportsClaw Orchestrator...');

  await alerter.logEvent(
    'orchestrator_start', 'info', 'orchestrator',
    'SportsClaw Orchestrator started',
    { tasks: Object.keys(SCHEDULE) }
  );

  // Set up interval-based tasks
  for (const [name, taskDef] of Object.entries(SCHEDULE)) {
    if (taskDef.interval) {
      const ms = parseInterval(taskDef.interval);
      console.log(`[sc-orchestrator] Scheduling ${name} every ${taskDef.interval} (${ms}ms)`);

      // Run once after short delay, then on interval
      setTimeout(() => runTask(name, taskDef), 5000 + Math.random() * 10000);
      setInterval(() => runTask(name, taskDef), ms);
    }
  }

  // Cron-based tasks: check every minute
  setInterval(async () => {
    for (const [name, taskDef] of Object.entries(SCHEDULE)) {
      if (taskDef.cron && matchesCron(taskDef.cron)) {
        runTask(name, taskDef);
      }
    }
  }, 60000);

  console.log('[sc-orchestrator] All tasks scheduled. Running...');
}

main().catch(err => {
  console.error('[sc-orchestrator] Fatal error:', err);
  process.exit(1);
});
