/**
 * Background Task Scheduler
 * 
 * Runs periodic tasks within the Next.js process:
 * - Bot autonomous posting (every 1 minute)
 * - Swarm gossip (every 5 minutes)
 * - Remote follows sync (every 10 minutes)
 * - Swarm announcement (on startup)
 */

import { processAllAutonomousBots } from '@/lib/bots/autonomous';
import { runGossipRound } from '@/lib/swarm/gossip';
import { announceToSeeds } from '@/lib/swarm/discovery';
import { getSwarmStats } from '@/lib/swarm/registry';
import { syncRemoteFollowsPosts } from '@/lib/background/remote-sync';
import { isPublicSwarmDomain } from '@/lib/swarm/node-domain';
import { processMentionDeliveryOutbox } from '@/lib/mentions/delivery';
import { processAllActiveBotMentions } from '@/lib/bots/mentionHandler';

const BOT_INTERVAL_MS = 60 * 1000; // 1 minute
const GOSSIP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
const REMOTE_SYNC_INTERVAL_MS = 60 * 1000; // 1 minute - keep feeds fresh
const MENTION_DELIVERY_INTERVAL_MS = 30 * 1000;
const STARTUP_DELAY_MS = 10 * 1000; // Wait 10s for server to be ready

let isStarted = false;

function log(category: string, message: string, data?: unknown) {
  const timestamp = new Date().toISOString();
  if (data) {
    console.log(`[${timestamp}] [${category}] ${message}`, JSON.stringify(data, null, 2));
  } else {
    console.log(`[${timestamp}] [${category}] ${message}`);
  }
}

async function runBotTasks() {
  try {
    const mentions = await processAllActiveBotMentions();
    const results = await processAllAutonomousBots();
    
    const posted = results.filter(r => r.result.posted).length;
    const errors = results.filter(r => r.error).length;
    
    if (posted > 0) {
      log('BOTS', `Created ${posted} posts`);
    } else if (results.length > 0) {
      // Log why bots didn't post
      const reasons = results
        .filter(r => !r.result.posted)
        .map(r => `${r.botHandle}: ${r.result.reason || r.error || 'unknown'}`)
        .slice(0, 5);
      
      if (reasons.length > 0) {
        log('BOTS', `${results.length} bots checked, no posts. Reasons: ${reasons.join('; ')}`);
      }
    } else {
      log('BOTS', 'No active bots found');
    }
    
    if (errors > 0) {
      const errorMsgs = results.filter(r => r.error).map(r => `${r.botHandle}: ${r.error}`);
      log('BOTS', `Errors: ${errorMsgs.join('; ')}`);
    }
    if (mentions.detected > 0 || mentions.responded > 0 || mentions.failed > 0) {
      log('BOTS', `Mentions: ${mentions.detected} detected, ${mentions.responded} responded, ${mentions.failed} failed`);
    }
  } catch (error) {
    log('BOTS', `Error: ${error}`);
  }
}

async function runMentionDeliveries() {
  try {
    const result = await processMentionDeliveryOutbox();
    if (result.delivered > 0 || result.retried > 0 || result.dead > 0) {
      log('MENTIONS', `Delivered ${result.delivered}, retrying ${result.retried}, dead-lettered ${result.dead}`);
    }
  } catch (error) {
    log('MENTIONS', `Outbox error: ${error}`);
  }
}

async function runSwarmGossip() {
  try {
    const stats = await getSwarmStats();

    // Recover from empty peer lists by periodically re-announcing to seeds.
    if (stats.activeNodes === 0) {
      const announceResult = await announceToSeeds();
      if (announceResult.successful.length > 0 || announceResult.failed.length > 0) {
        log('SWARM', `Re-announced to seeds: ${announceResult.successful.length} successful, ${announceResult.failed.length} failed`);
      }
    }

    const result = await runGossipRound();
    if (result.contacted > 0) {
      log('SWARM', `Gossip: contacted ${result.contacted}, successful ${result.successful}, received ${result.totalNodesReceived} nodes`);
    } else if (stats.activeNodes === 0) {
      log('SWARM', 'No active swarm peers yet');
    }
  } catch (error) {
    log('SWARM', `Gossip error: ${error}`);
  }
}

async function announceToSwarm() {
  try {
    const result = await announceToSeeds();
    log('SWARM', `Announced to seeds: ${result.successful.length} successful, ${result.failed.length} failed`);
    
    const stats = await getSwarmStats();
    log('SWARM', `Network: ${stats.activeNodes} active nodes, ${stats.totalUsers} users, ${stats.totalPosts} posts`);
  } catch (error) {
    log('SWARM', `Announcement error: ${error}`);
  }
}

async function runRemoteSync(origin: string) {
  try {
    const result = await syncRemoteFollowsPosts(origin);
    if (result.synced > 0 || result.errors > 0) {
      log('REMOTE_SYNC', `Synced ${result.synced} users, skipped ${result.skipped}, errors ${result.errors}`);
      if (result.details.length > 0) {
        const newPosts = result.details.filter(d => d.cached > 0);
        if (newPosts.length > 0) {
          log('REMOTE_SYNC', `New posts: ${newPosts.map(d => `${d.handle}: ${d.cached}`).join(', ')}`);
        }
      }
    }
  } catch (error) {
    log('REMOTE_SYNC', `Error: ${error}`);
  }
}

export function startBackgroundTasks(origin?: string) {
  // Prevent double-start (Next.js can call register() multiple times in dev)
  if (isStarted) return;
  isStarted = true;

  // Default origin for remote sync (can be overridden)
  const syncOrigin = origin || process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:43821';
  const publicSwarmEnabled = isPublicSwarmDomain(process.env.NEXT_PUBLIC_NODE_DOMAIN);

  log('STARTUP', 'Background task scheduler starting...');
  log('STARTUP', `Bot interval: ${BOT_INTERVAL_MS / 1000}s, Gossip interval: ${GOSSIP_INTERVAL_MS / 1000}s, Remote sync interval: ${REMOTE_SYNC_INTERVAL_MS / 1000}s`);

  // Wait for server to be fully ready before starting tasks
  setTimeout(async () => {
    log('STARTUP', 'Starting background tasks...');
    
    if (publicSwarmEnabled) {
      // Announce to swarm on startup
      await announceToSwarm();
    } else {
      log('SWARM', 'Public swarm disabled: NEXT_PUBLIC_NODE_DOMAIN is not a public ICANN domain');
    }
    
    // Run initial bot check
    await runBotTasks();
    await runMentionDeliveries();
    
    // Run initial remote sync (after 15s to let server stabilize)
    setTimeout(() => runRemoteSync(syncOrigin), 15 * 1000);
    
    // Schedule recurring tasks
    setInterval(runBotTasks, BOT_INTERVAL_MS);
    setInterval(runMentionDeliveries, MENTION_DELIVERY_INTERVAL_MS);
    if (publicSwarmEnabled) {
      setInterval(runSwarmGossip, GOSSIP_INTERVAL_MS);
    }
    setInterval(() => runRemoteSync(syncOrigin), REMOTE_SYNC_INTERVAL_MS);
    
    // First gossip after 30s (let announcement propagate)
    if (publicSwarmEnabled) {
      setTimeout(runSwarmGossip, 30 * 1000);
    }
    
    log('STARTUP', 'Background tasks running');
  }, STARTUP_DELAY_MS);
}
