/**
 * Alert System Agent
 * 
 * Monitors for significant events and sends notifications via email,
 * dashboard updates, or other channels. Integrates with Gmail MCP for alerts.
 * 
 * Usage:
 *   agent-alert -- --investigation <id> --channel <email|dashboard>
 */

import { Type } from "@sinclair/typebox";
import { query } from "../db.js";

// ─── CLI Arguments ──────────────────────────────────────────────────────────

interface AlertArgs {
  investigation: string;
  channel: "email" | "dashboard" | "all";
  recipientEmail?: string;
  minRiskScore: number;
  checkInterval: number;
}

function parseArgs(): AlertArgs {
  const args = process.argv.slice(2);
  const config: AlertArgs = {
    investigation: "",
    channel: "all",
    minRiskScore: 30,
    checkInterval: 15,
  };

  for (let i = 0; i < args.length; i++) {
    switch (args[i]) {
      case "--investigation":
      case "-i":
        config.investigation = args[++i];
        break;
      case "--channel":
        config.channel = args[++i] as AlertArgs["channel"];
        break;
      case "--email":
        config.recipientEmail = args[++i];
        break;
      case "--min-risk":
        config.minRiskScore = parseInt(args[++i], 10);
        break;
      case "--interval":
        config.checkInterval = parseInt(args[++i], 10);
        break;
    }
  }

  if (!config.investigation) {
    console.error("Error: --investigation <id> is required");
    process.exit(1);
  }

  return config;
}

// ─── Alert Types ────────────────────────────────────────────────────────────

type AlertType =
  | "ACTIVITY_SPIKE"
  | "HIGH_RISK_CONTENT"
  | "COORDINATION_DETECTED"
  | "NEW_ENTITY"
  | "CLAIM_VERIFIED"
  | "MONITORING_FAILURE";

interface Alert {
  id: string;
  type: AlertType;
  investigationId: string;
  severity: "low" | "medium" | "high" | "critical";
  title: string;
  message: string;
  data: Record<string, unknown>;
  createdAt: Date;
  acknowledged: boolean;
}

async function createAlert(
  type: AlertType,
  investigationId: string,
  severity: Alert["severity"],
  title: string,
  message: string,
  data: Record<string, unknown>
): Promise<Alert> {
  const alert: Alert = {
    id: `alert_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
    type,
    investigationId,
    severity,
    title,
    message,
    data,
    createdAt: new Date(),
    acknowledged: false,
  };

  // Save to database
  await query(
    `INSERT INTO annotations (investigation_id, ref_type, ref_id, analyst, note, confidence, created_at)
     VALUES ($1, 'alert', $2, 'system', $3, $4, NOW())`,
    [
      investigationId,
      alert.id,
      `[${severity.toUpperCase()}] ${title}: ${message}`,
      severity === "critical" ? 100 : severity === "high" ? 80 : severity === "medium" ? 60 : 40,
    ]
  );

  return alert;
}

// ─── Alert Detection ────────────────────────────────────────────────────────

async function checkActivitySpikes(
  investigationId: string,
  sinceMinutes: number
): Promise<Alert[]> {
  const alerts: Alert[] = [];
  const since = new Date(Date.now() - sinceMinutes * 60 * 1000);

  // Check for post volume spikes
  const postResult = await query(
    `SELECT entity_id, COUNT(*) as post_count
     FROM content
     WHERE investigation_id = $1
     AND type = 'post'
     AND collected_at > $2
     GROUP BY entity_id
     HAVING COUNT(*) > 10`,
    [investigationId, since]
  );

  for (const row of postResult.rows) {
    const entityResult = await query(
      "SELECT name, url FROM entities WHERE id = $1",
      [row.entity_id]
    );
    const entity = entityResult.rows[0];

    const alert = await createAlert(
      "ACTIVITY_SPIKE",
      investigationId,
      "high",
      `Activity Spike Detected`,
      `${entity.name || entity.url} posted ${row.post_count} times in ${sinceMinutes} minutes`,
      {
        entityId: row.entity_id,
        entityName: entity.name,
        entityUrl: entity.url,
        postCount: row.post_count,
        timeWindow: sinceMinutes,
      }
    );
    alerts.push(alert);
  }

  // Check for engagement spikes
  const engagementResult = await query(
    `SELECT id, entity_id, text, 
            (COALESCE(likes, 0) + COALESCE(shares, 0) + COALESCE(comments, 0)) as total_engagement
     FROM content
     WHERE investigation_id = $1
     AND collected_at > $2
     AND (COALESCE(likes, 0) + COALESCE(shares, 0) + COALESCE(comments, 0)) > 1000
     ORDER BY total_engagement DESC`,
    [investigationId, since]
  );

  for (const row of engagementResult.rows) {
    const totalEngagement = Number(row.total_engagement);
    const alert = await createAlert(
      "HIGH_RISK_CONTENT",
      investigationId,
      totalEngagement > 5000 ? "critical" : "high",
      `Viral Content Alert`,
      `Content with ${totalEngagement} engagements detected`,
      {
        contentId: row.id,
        entityId: row.entity_id,
        engagement: totalEngagement,
        textPreview: row.text ? String(row.text).slice(0, 200) : null,
      }
    );
    alerts.push(alert);
  }

  return alerts;
}

async function checkHighRiskContent(
  investigationId: string,
  minRiskScore: number,
  sinceMinutes: number
): Promise<Alert[]> {
  const alerts: Alert[] = [];
  const since = new Date(Date.now() - sinceMinutes * 60 * 1000);

  // Check annotations for high-risk content
  const result = await query(
    `SELECT a.ref_id, a.note, a.confidence, c.entity_id, c.text, c.type
     FROM annotations a
     JOIN content c ON c.id = a.ref_id
     WHERE a.investigation_id = $1
     AND a.ref_type = 'content'
     AND a.confidence >= $2
     AND a.created_at > $3
     ORDER BY a.confidence DESC
     LIMIT 10`,
    [investigationId, minRiskScore, since]
  );

  for (const row of result.rows) {
    const confidence = Number(row.confidence);
    const alert = await createAlert(
      "HIGH_RISK_CONTENT",
      investigationId,
      confidence >= 80 ? "critical" : "high",
      `High-Risk Content Detected`,
      `Content flagged with risk score ${confidence}`,
      {
        contentId: row.ref_id,
        entityId: row.entity_id,
        riskScore: confidence,
        contentType: row.type,
        note: row.note,
        textPreview: row.text ? String(row.text).slice(0, 200) : null,
      }
    );
    alerts.push(alert);
  }

  return alerts;
}

async function checkNewEntities(
  investigationId: string,
  sinceMinutes: number
): Promise<Alert[]> {
  const alerts: Alert[] = [];
  const since = new Date(Date.now() - sinceMinutes * 60 * 1000);

  const result = await query(
    `SELECT id, type, name, url, platform, collected_at
     FROM entities
     WHERE investigation_id = $1
     AND collected_at > $2
     ORDER BY collected_at DESC`,
    [investigationId, since]
  );

  if (result.rows.length >= 5) {
    const alert = await createAlert(
      "NEW_ENTITY",
      investigationId,
      "medium",
      `Multiple New Entities Detected`,
      `${result.rows.length} new entities added in ${sinceMinutes} minutes`,
      {
        entityCount: result.rows.length,
        entities: result.rows.map((r: any) => ({
          id: r.id,
          type: r.type,
          name: r.name,
          platform: r.platform,
        })),
      }
    );
    alerts.push(alert);
  }

  return alerts;
}

// ─── Alert Delivery ─────────────────────────────────────────────────────────

async function sendEmailAlert(alert: Alert, recipientEmail: string) {
  console.log(`\n📧 Email Alert:`);
  console.log(`To: ${recipientEmail}`);
  console.log(`Subject: [${alert.severity.toUpperCase()}] ${alert.title}`);
  console.log(`\n${alert.message}`);
  console.log(`\nDetails:`, JSON.stringify(alert.data, null, 2));

  // TODO: Integrate with gmcli skill to send actual email
  // Example: Use sendUserMessage to trigger gmcli send-email command
  
  /*
  const emailBody = `
    <h2>${alert.title}</h2>
    <p><strong>Severity:</strong> ${alert.severity.toUpperCase()}</p>
    <p><strong>Investigation:</strong> ${alert.investigationId}</p>
    <p>${alert.message}</p>
    <h3>Details</h3>
    <pre>${JSON.stringify(alert.data, null, 2)}</pre>
    <p><small>Generated by CultGuard Alert System at ${alert.createdAt.toISOString()}</small></p>
  `;

  // Would use gmcli skill here
  */
}

async function updateDashboard(alert: Alert) {
  console.log(`\n📊 Dashboard Update:`);
  console.log(`Alert ID: ${alert.id}`);
  console.log(`Type: ${alert.type}`);
  console.log(`Severity: ${alert.severity}`);
  console.log(`Title: ${alert.title}`);

  // TODO: Update Metabase or custom dashboard
  // Could insert into a dashboard_alerts table for Metabase to query
}

async function deliverAlert(alert: Alert, channel: AlertArgs["channel"], recipientEmail?: string) {
  if (channel === "email" || channel === "all") {
    if (recipientEmail) {
      await sendEmailAlert(alert, recipientEmail);
    } else {
      console.log("[Alert] Email channel configured but no recipient specified");
    }
  }

  if (channel === "dashboard" || channel === "all") {
    await updateDashboard(alert);
  }
}

// ─── Alert Loop ─────────────────────────────────────────────────────────────

async function alertLoop(config: AlertArgs) {
  console.log("🚨 CultGuard Alert System");
  console.log(`Investigation: ${config.investigation}`);
  console.log(`Channel: ${config.channel}`);
  console.log(`Min risk score: ${config.minRiskScore}`);
  console.log(`Check interval: ${config.checkInterval} minutes\n`);

  let checkCount = 0;

  while (true) {
    checkCount++;
    console.log(`\n${"=".repeat(60)}`);
    console.log(`[Check ${checkCount}] ${new Date().toISOString()}`);
    console.log(`${"=".repeat(60)}`);

    try {
      const allAlerts: Alert[] = [];

      // Check for activity spikes (last 30 minutes)
      console.log(`[Alert] Checking activity spikes...`);
      const spikeAlerts = await checkActivitySpikes(config.investigation, 30);
      allAlerts.push(...spikeAlerts);

      // Check for high-risk content
      console.log(`[Alert] Checking high-risk content...`);
      const riskAlerts = await checkHighRiskContent(
        config.investigation,
        config.minRiskScore,
        60
      );
      allAlerts.push(...riskAlerts);

      // Check for new entities
      console.log(`[Alert] Checking new entities...`);
      const entityAlerts = await checkNewEntities(config.investigation, 60);
      allAlerts.push(...entityAlerts);

      // Deliver alerts
      if (allAlerts.length > 0) {
        console.log(`\n🚨 ${allAlerts.length} alert(s) to deliver:`);
        for (const alert of allAlerts) {
          await deliverAlert(alert, config.channel, config.recipientEmail);
        }
      } else {
        console.log(`[Alert] No new alerts`);
      }
    } catch (error) {
      console.error(`[Alert] Check failed:`, error);
      
      // Create failure alert
      await createAlert(
        "MONITORING_FAILURE",
        config.investigation,
        "high",
        "Alert System Error",
        error instanceof Error ? error.message : "Unknown error",
        { checkCount, timestamp: new Date().toISOString() }
      );
    }

    // Wait for next check
    const waitMs = config.checkInterval * 60 * 1000;
    console.log(`\n[Alert] Next check in ${config.checkInterval} minutes`);
    await new Promise(resolve => setTimeout(resolve, waitMs));
  }
}

// ─── Main Entry Point ───────────────────────────────────────────────────────

async function main() {
  try {
    const config = parseArgs();
    await alertLoop(config);
  } catch (error) {
    console.error("\n💀 Alert system crashed:", error);
    process.exit(1);
  }
}

main();
