import type { IncomingMessage, ServerResponse } from "node:http";
import {
  getRules,
  getRule,
  createRule,
  updateRule,
  deleteRule,
  getAlertHistory,
  getAlertHistoryCount,
  clearAlertState,
  type AlertRule,
} from "../db.js";
import { runEvaluator } from "../alerting/evaluator.js";

function json(res: ServerResponse, data: unknown, status = 200): void {
  res.writeHead(status, { "Content-Type": "application/json" });
  res.end(JSON.stringify(data));
}

function error(res: ServerResponse, message: string, status = 400): void {
  json(res, { error: message }, status);
}

function readBody(req: IncomingMessage): Promise<unknown> {
  return new Promise((resolve) => {
    let data = "";
    req.on("data", (chunk: Buffer) => { data += chunk; });
    req.on("end", () => {
      try { resolve(JSON.parse(data || "{}")); }
      catch { resolve({}); }
    });
  });
}

export function handleGetRules(_req: IncomingMessage, res: ServerResponse): void {
  json(res, getRules());
}

export function handleGetRule(_req: IncomingMessage, res: ServerResponse, id: string): void {
  const rule = getRule(id);
  if (!rule) return error(res, "Rule not found", 404);
  json(res, rule);
}

export async function handleCreateRule(req: IncomingMessage, res: ServerResponse): Promise<void> {
  const body = await readBody(req);
  if (typeof body !== "object" || body === null) return error(res, "Invalid body");

  const b = body as Record<string, unknown>;
  const name = typeof b.name === "string" ? b.name.trim() : null;
  if (!name) return error(res, "name is required");

  const target_type = b.target_type as string;
  if (!["host", "service", "network", "site"].includes(target_type)) {
    return error(res, "target_type must be one of: host, service, network, site");
  }

  const condition = b.condition as AlertRule["condition"] | undefined;
  if (!condition || !["state", "threshold"].includes(condition.kind)) {
    return error(res, "condition.kind must be 'state' or 'threshold'");
  }

  const severity = (b.severity as string) ?? "warning";
  if (!["warning", "critical"].includes(severity)) {
    return error(res, "severity must be 'warning' or 'critical'");
  }

  const rule = createRule({
    id: crypto.randomUUID(),
    name,
    enabled: b.enabled !== false,
    target_type: target_type as AlertRule["target_type"],
    target_id: typeof b.target_id === "string" ? b.target_id : null,
    condition,
    severity: severity as AlertRule["severity"],
    cooldown_seconds: typeof b.cooldown_seconds === "number" ? b.cooldown_seconds : 300,
    channels: Array.isArray(b.channels) ? b.channels as string[] : ["notifications", "chronicle"],
  });

  json(res, rule, 201);
}

export async function handleUpdateRule(req: IncomingMessage, res: ServerResponse, id: string): Promise<void> {
  const existing = getRule(id);
  if (!existing) return error(res, "Rule not found", 404);

  const body = await readBody(req);
  if (typeof body !== "object" || body === null) return error(res, "Invalid body");

  const b = body as Record<string, unknown>;
  const patch: Partial<Omit<AlertRule, "id" | "created_at" | "updated_at">> = {};

  if (typeof b.name === "string") patch.name = b.name.trim();
  if (typeof b.enabled === "boolean") patch.enabled = b.enabled;
  if (typeof b.target_id === "string") patch.target_id = b.target_id;
  if (b.target_id === null) patch.target_id = null;
  if (b.condition !== undefined) patch.condition = b.condition as AlertRule["condition"];
  if (typeof b.severity === "string" && ["warning", "critical"].includes(b.severity)) {
    patch.severity = b.severity as AlertRule["severity"];
  }
  if (typeof b.cooldown_seconds === "number") patch.cooldown_seconds = b.cooldown_seconds;
  if (Array.isArray(b.channels)) patch.channels = b.channels as string[];

  const updated = updateRule(id, patch);
  json(res, updated);
}

export function handleDeleteRule(_req: IncomingMessage, res: ServerResponse, id: string): void {
  const deleted = deleteRule(id);
  if (!deleted) return error(res, "Rule not found", 404);
  clearAlertState(id);
  json(res, { ok: true });
}

export function handleGetHistory(req: IncomingMessage, res: ServerResponse): void {
  const url = new URL(req.url ?? "/", "http://localhost");
  const limit  = Math.min(parseInt(url.searchParams.get("limit")  ?? "50",  10), 200);
  const offset = parseInt(url.searchParams.get("offset") ?? "0",  10);
  const total  = getAlertHistoryCount();
  const rows   = getAlertHistory(limit, offset);
  json(res, { total, limit, offset, items: rows });
}

export async function handleTestFire(req: IncomingMessage, res: ServerResponse): Promise<void> {
  const body = await readBody(req);
  const b = (typeof body === "object" && body !== null ? body : {}) as Record<string, unknown>;
  const ruleId = typeof b.rule_id === "string" ? b.rule_id : null;

  if (ruleId) {
    const rule = getRule(ruleId);
    if (!rule) return error(res, "Rule not found", 404);
  }

  try {
    await runEvaluator();
    json(res, { ok: true, message: "Evaluation pass complete" });
  } catch (e) {
    json(res, { error: (e as Error).message }, 500);
  }
}
