import { randomUUID } from "node:crypto";
import { NextResponse } from "next/server";
import { getDbPool } from "@/db";
import { getSession } from "@/lib/auth";
import { ensureDefaultRuleSets } from "@/lib/default-rules";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

const vehicleTypes = new Set(["light", "motorcycle", "heavy"]);
const actions = new Set(["approve", "approve_with_notes", "human_review", "retriage", "reject", "alert"]);

async function requireAdmin() {
  const session = await getSession();
  return session?.role === "capital_admin" ? session : null;
}

export async function GET(request: Request) {
  const session = await requireAdmin();
  if (!session) return NextResponse.json({ error: "Somente administradores da Capital podem configurar regras." }, { status: 403 });

  const db = getDbPool();
  const query = new URL(request.url).searchParams;
  const tenantId = query.get("tenantId") || "";
  const vehicleType = query.get("vehicleType") || "light";
  if (!vehicleTypes.has(vehicleType)) return NextResponse.json({ error: "Tipo de veículo inválido." }, { status: 400 });

  const [tenantRows] = await db.execute("SELECT id, name, slug FROM tenants WHERE status = 'active' ORDER BY name");
  const tenants = tenantRows as Record<string, unknown>[];
  const selectedTenantId = tenantId || String(tenants[0]?.id || "");
  if (!selectedTenantId) return NextResponse.json({ tenants: [], ruleSet: null, rules: [] });

  const provisionedVehicleTypes = await ensureDefaultRuleSets(selectedTenantId);

  const [setRows] = await db.execute(
    "SELECT id, name, version, confidence_threshold, approved_limit, review_limit, rejected_limit, created_at FROM rule_sets WHERE tenant_id = ? AND vehicle_type = ? AND status = 'active' ORDER BY created_at DESC LIMIT 1",
    [selectedTenantId, vehicleType],
  );
  const ruleSet = (setRows as Record<string, unknown>[])[0] ?? null;
  if (!ruleSet) return NextResponse.json({ tenants, ruleSet: null, rules: [] });
  const [ruleRows] = await db.execute(
    "SELECT id, code, name, rule_type, points, action, condition_json, is_enabled FROM rules WHERE rule_set_id = ? ORDER BY points DESC, name",
    [String(ruleSet.id)],
  );
  return NextResponse.json({ tenants, ruleSet, rules: ruleRows, provisionedVehicleTypes });
}

export async function POST(request: Request) {
  const session = await requireAdmin();
  if (!session) return NextResponse.json({ error: "Somente administradores da Capital podem publicar regras." }, { status: 403 });
  try {
    const body = await request.json();
    const tenantId = String(body.tenantId || "");
    const vehicleType = String(body.vehicleType || "");
    const sourceRuleSetId = String(body.sourceRuleSetId || "");
    const name = String(body.name || "Conjunto de regras").trim().slice(0, 160);
    if (!tenantId || !sourceRuleSetId || !vehicleTypes.has(vehicleType)) return NextResponse.json({ error: "Selecione cliente, tipo de veículo e um conjunto de regras válido." }, { status: 400 });

    const threshold = Number(body.confidenceThreshold);
    const approvedLimit = Number(body.approvedLimit);
    const reviewLimit = Number(body.reviewLimit);
    const rejectedLimit = Number(body.rejectedLimit);
    if (![threshold, approvedLimit, reviewLimit, rejectedLimit].every(Number.isFinite) || threshold < 0 || threshold > 100 || approvedLimit < 0 || reviewLimit < approvedLimit || rejectedLimit < reviewLimit) {
      return NextResponse.json({ error: "Revise os limites: confiança entre 0 e 100 e faixas de pontuação em ordem crescente." }, { status: 400 });
    }

    const rules = Array.isArray(body.rules) ? body.rules : [];
    if (!rules.length) return NextResponse.json({ error: "Mantenha ao menos uma regra no conjunto." }, { status: 400 });
    const db = getDbPool();
    const [sourceRows] = await db.execute("SELECT id FROM rule_sets WHERE id = ? AND tenant_id = ? AND vehicle_type = ? LIMIT 1", [sourceRuleSetId, tenantId, vehicleType]);
    if (!(sourceRows as unknown[]).length) return NextResponse.json({ error: "Conjunto de regras não encontrado." }, { status: 404 });

    const now = new Date();
    const version = `capital-${now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}`;
    const ruleSetId = randomUUID();
    const connection = await db.getConnection();
    try {
      await connection.beginTransaction();
      await connection.execute("UPDATE rule_sets SET status = 'archived' WHERE tenant_id = ? AND vehicle_type = ? AND status = 'active'", [tenantId, vehicleType]);
      await connection.execute(
        "INSERT INTO rule_sets (id, tenant_id, vehicle_type, name, version, status, confidence_threshold, approved_limit, review_limit, rejected_limit) VALUES (?, ?, ?, ?, ?, 'active', ?, ?, ?, ?)",
        [ruleSetId, tenantId, vehicleType, name, version, threshold, approvedLimit, reviewLimit, rejectedLimit],
      );
      for (const rule of rules) {
        const code = String(rule.code || "").trim().slice(0, 100);
        const ruleName = String(rule.name || "").trim().slice(0, 180);
        const ruleType = String(rule.rule_type || "scoring");
        const points = Number(rule.points);
        const action = String(rule.action || "alert");
        if (!code || !ruleName || !Number.isFinite(points) || !actions.has(action) || !["blocking", "scoring", "retriage", "alert", "routing"].includes(ruleType)) throw new Error("RULE_INVALID");
        const conditionJson = typeof rule.condition_json === "string" ? rule.condition_json : JSON.stringify(rule.condition_json || {});
        let condition: { type?: string; values?: unknown[] };
        try { condition = JSON.parse(conditionJson) as { type?: string; values?: unknown[] }; } catch { throw new Error("RULE_INVALID"); }
        if (!condition?.type || !["finding_contains", "min_confidence", "requires_human", "ai_status", "manual_assessment"].includes(condition.type)) throw new Error("RULE_INVALID");
        if (["finding_contains", "ai_status", "manual_assessment"].includes(condition.type) && (!Array.isArray(condition.values) || !condition.values.some((value) => String(value).trim()))) throw new Error("RULE_INVALID");
        await connection.execute(
          "INSERT INTO rules (id, rule_set_id, code, name, rule_type, points, action, condition_json, is_enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
          [randomUUID(), ruleSetId, code, ruleName, ruleType, points, action, conditionJson, Boolean(rule.is_enabled)],
        );
      }
      await connection.commit();
    } catch (error) {
      await connection.rollback();
      throw error;
    } finally {
      connection.release();
    }
    return NextResponse.json({ message: `Nova versão ${version} publicada. Vistorias já concluídas mantêm a versão anterior no histórico.`, version }, { status: 201 });
  } catch (error) {
    console.error("Erro ao publicar regras", error);
    if (error instanceof Error && error.message === "RULE_INVALID") return NextResponse.json({ error: "Há uma regra com dados inválidos." }, { status: 400 });
    return NextResponse.json({ error: "Não foi possível publicar as regras." }, { status: 500 });
  }
}
