/**
 * Social Engine — Orchestrator (PM2 Process)
 * Runs on a 20-minute interval, executing phases sequentially:
 *   1. Trend Intelligence → detect signals from 5 data sources
 *   2. Persona Router → assign trends to personas
 *   3. Content Generator → Grok generates persona-voiced text
 *   4. Content Multiplier → expand to threads + FLUX images
 *   5. Compliance Gate → validate against brand rules
 *   6. Distributor → post to Twitter/X
 *   7. Performance Tracker → collect engagement metrics (every 2h)
 *
 * Coexists with existing twitter-agent.worker — shares tweet budget.
 */
import dotenv from 'dotenv';
dotenv.config({ path: '/var/www/html/rainmaker/backend/.env' });

import { detectTrends } from './trend-intelligence';
import { routeTrendsToPersonas } from './persona-router';
import { generateContent } from './content-generator';
import { multiplyContent } from './content-multiplier';
import { runComplianceGate } from './compliance-gate';
import { distributeContent } from './distributor';
import { trackPerformance, runDailyRollup } from './performance-tracker';
import { createEngineRun, updateEngineRun } from './data-queries';

const INTERVAL_MS = 20 * 60 * 1000; // 20 minutes
const PERFORMANCE_INTERVAL_H = 2; // Track performance every 2 hours

let running = false;
let shutdownRequested = false;
let lastPerformanceRun = 0;
let lastDailyRollup = 0;

// ── ET Timezone Helpers ──

function getETHour(): number {
  const etString = new Date().toLocaleString('en-US', { timeZone: 'America/New_York', hour: 'numeric', hour12: false });
  const h = parseInt(etString);
  return h === 24 ? 0 : h;
}

function isContentWindow(): boolean {
  const hour = getETHour();
  // Active posting windows: 6-11 AM, 11 AM-3 PM, 3-7 PM, 8-11 PM ET
  return hour >= 6 && hour <= 23;
}

// ── Main Orchestrator ──

async function runCycle(): Promise<void> {
  if (running) {
    console.log('[social-engine] Previous cycle still running, skipping');
    return;
  }

  running = true;
  const startTime = Date.now();
  const runId = await createEngineRun('scheduled_cycle');
  const counters = { trends_found: 0, content_created: 0, content_posted: 0 };

  try {
    const etHour = getETHour();
    console.log(`\n[social-engine] ═══ Cycle Start (${new Date().toISOString()}, ET hour: ${etHour}) ═══`);

    // Phase 1: Detect trends (always runs)
    try {
      counters.trends_found = await detectTrends();
    } catch (err: any) {
      console.error('[social-engine] Phase 1 (trends) failed:', err.message);
    }

    // Phases 2-6 only run during content windows
    if (isContentWindow()) {
      // Phase 2: Route trends to personas
      let pairs: any[] = [];
      try {
        pairs = await routeTrendsToPersonas();
      } catch (err: any) {
        console.error('[social-engine] Phase 2 (routing) failed:', err.message);
      }

      // Phase 3: Generate content
      if (pairs.length > 0) {
        try {
          counters.content_created = await generateContent(pairs);
        } catch (err: any) {
          console.error('[social-engine] Phase 3 (generation) failed:', err.message);
        }
      }

      // Phase 4: Multiply content (threads + images)
      try {
        await multiplyContent();
      } catch (err: any) {
        console.error('[social-engine] Phase 4 (multiplier) failed:', err.message);
      }

      // Phase 5: Compliance gate
      try {
        await runComplianceGate();
      } catch (err: any) {
        console.error('[social-engine] Phase 5 (compliance) failed:', err.message);
      }

      // Phase 6: Distribute to Twitter
      try {
        counters.content_posted = await distributeContent();
      } catch (err: any) {
        console.error('[social-engine] Phase 6 (distribution) failed:', err.message);
      }
    } else {
      console.log(`[social-engine] Outside content window (ET hour ${etHour}), skipping phases 2-6`);
    }

    // Phase 7: Performance tracking (every 2 hours)
    const now = Date.now();
    if (now - lastPerformanceRun > PERFORMANCE_INTERVAL_H * 60 * 60 * 1000) {
      try {
        await trackPerformance();
        lastPerformanceRun = now;
      } catch (err: any) {
        console.error('[social-engine] Phase 7 (performance) failed:', err.message);
      }
    }

    // Daily rollup at midnight ET (hour 0)
    if (getETHour() === 0 && now - lastDailyRollup > 20 * 60 * 60 * 1000) {
      try {
        await runDailyRollup();
        lastDailyRollup = now;
      } catch (err: any) {
        console.error('[social-engine] Daily rollup failed:', err.message);
      }
    }

    const durationMs = Date.now() - startTime;
    await updateEngineRun(runId, 'completed', counters, durationMs);
    console.log(`[social-engine] ═══ Cycle Complete (${durationMs}ms) — trends:${counters.trends_found} created:${counters.content_created} posted:${counters.content_posted} ═══\n`);
  } catch (err: any) {
    const durationMs = Date.now() - startTime;
    await updateEngineRun(runId, 'failed', counters, durationMs, err.message);
    console.error('[social-engine] Cycle failed:', err.message);
  } finally {
    running = false;
  }
}

// ── Lifecycle ──

function scheduleNext(): void {
  if (shutdownRequested) return;
  setTimeout(() => {
    runCycle().then(scheduleNext).catch(() => scheduleNext());
  }, INTERVAL_MS);
}

// Graceful shutdown
process.on('SIGINT', () => {
  console.log('[social-engine] SIGINT received, shutting down...');
  shutdownRequested = true;
  if (!running) process.exit(0);
});

process.on('SIGTERM', () => {
  console.log('[social-engine] SIGTERM received, shutting down...');
  shutdownRequested = true;
  if (!running) process.exit(0);
});

// Start
console.log('[social-engine] Starting Social Engine Worker...');
console.log(`[social-engine] Interval: ${INTERVAL_MS / 1000}s | DRY_RUN: ${process.env.TWITTER_DRY_RUN || 'false'}`);
runCycle().then(scheduleNext).catch(scheduleNext);
