import Database from "better-sqlite3";
import { existsSync } from "node:fs";
import type { AlertRule, AlertHistoryRow } from "../db.js";

const NOTIFICATIONS_URL = process.env.NOTIFICATIONS_SERVICE_URL ?? "http://127.0.0.1:8087";
const IMESSAGE_HOST_URL  = process.env.IMESSAGE_HOST_URL ?? "http://127.0.0.1:8080";
const IMESSAGE_RECIPIENT = process.env.ALERT_IMESSAGE_RECIPIENT ?? "";

// Chronicle DB path must be configured via environment variable
const CHRONICLE_DB_PATH = process.env.CHRONICLE_DB_PATH ?? "";

export interface AlertPayload {
  rule: AlertRule;
  historyRow: AlertHistoryRow;
  targetName: string;
  message: string;
  isRecovery: boolean;
}

async function deliverNotification(payload: AlertPayload): Promise<void> {
  const { rule, message, isRecovery } = payload;
  const title = isRecovery
    ? `Resolved: ${rule.name}`
    : rule.severity === "critical" ? `Alert: ${rule.name}` : `Warning: ${rule.name}`;

  try {
    const res = await fetch(`${NOTIFICATIONS_URL}/notifications`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        title,
        description: message,
        source: "status-alerting",
        level: isRecovery ? "info" : rule.severity === "critical" ? "error" : "warning",
      }),
    });
    if (!res.ok) {
      console.error(`[channels] Notifications delivery failed: HTTP ${res.status}`);
    }
  } catch (e) {
    console.error(`[channels] Notifications delivery error:`, (e as Error).message);
  }
}

async function deliverImessage(payload: AlertPayload): Promise<void> {
  if (!IMESSAGE_RECIPIENT) return;

  const { rule, message, targetName, isRecovery } = payload;
  const prefix = isRecovery
    ? `[RESOLVED] ${rule.name}`
    : rule.severity === "critical" ? `[ALERT] ${rule.name}` : `[WARNING] ${rule.name}`;

  const text = `${prefix}\n${targetName}: ${message}\n${new Date().toLocaleString()}`;

  try {
    const res = await fetch(`${IMESSAGE_HOST_URL}/send`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ recipient: IMESSAGE_RECIPIENT, message: text }),
    });
    if (!res.ok) {
      console.error(`[channels] iMessage delivery failed: HTTP ${res.status}`);
    }
  } catch (e) {
    console.error(`[channels] iMessage delivery error:`, (e as Error).message);
  }
}

let _chronicleDb: Database.Database | null = null;

function getChronicleDb(): Database.Database | null {
  if (_chronicleDb) return _chronicleDb;
  if (!CHRONICLE_DB_PATH || !existsSync(CHRONICLE_DB_PATH)) {
    if (CHRONICLE_DB_PATH) {
      console.warn(`[channels] Chronicle DB not found at ${CHRONICLE_DB_PATH}, skipping chronicle delivery`);
    }
    return null;
  }
  try {
    _chronicleDb = new Database(CHRONICLE_DB_PATH);
    _chronicleDb.pragma("journal_mode = WAL");
    return _chronicleDb;
  } catch (e) {
    console.error(`[channels] Failed to open Chronicle DB:`, (e as Error).message);
    return null;
  }
}

function deliverChronicle(payload: AlertPayload): void {
  const db = getChronicleDb();
  if (!db) return;

  const { rule, historyRow, message, isRecovery } = payload;
  const now = Date.now();
  const today = new Date().toISOString().slice(0, 10);
  const eventType = isRecovery ? "alert_resolved" : "alert_firing";
  const title = isRecovery
    ? `Resolved: ${rule.name} — ${historyRow.target_name ?? historyRow.target_key}`
    : `Alert: ${rule.name} — ${historyRow.target_name ?? historyRow.target_key}`;

  try {
    db.prepare(`
      INSERT OR REPLACE INTO chronicle_events
        (id, date, timestamp, source, type, title, body, metadata)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    `).run(
      historyRow.id,
      today,
      now,
      "status",
      eventType,
      title,
      message,
      JSON.stringify({
        rule_id: rule.id,
        rule_name: rule.name,
        target_key: historyRow.target_key,
        target_name: historyRow.target_name,
        severity: rule.severity,
        fired_at: historyRow.fired_at,
        resolved_at: historyRow.resolved_at ?? undefined,
      }),
    );
  } catch (e) {
    console.error(`[channels] Chronicle write error:`, (e as Error).message);
  }
}

export async function dispatch(payload: AlertPayload): Promise<void> {
  const { rule } = payload;
  const promises: Promise<void>[] = [];

  if (rule.channels.includes("notifications")) {
    promises.push(deliverNotification(payload));
  }
  if (rule.channels.includes("imessage")) {
    promises.push(deliverImessage(payload));
  }
  if (rule.channels.includes("chronicle")) {
    deliverChronicle(payload);
  }

  if (promises.length > 0) {
    await Promise.allSettled(promises);
  }
}
