import assert from "node:assert/strict";
import test from "node:test";
import {
  computeProcess,
  detectEmergency,
  detectStopPath,
  missingRequired,
  STEP_META,
} from "@/lib/mortgage/gates";
import { emptyProfile, type ApplicantProfile } from "@/lib/mortgage/schema";
import { mergeProfile } from "@/lib/mortgage/extract";

function base(extra: Partial<ApplicantProfile> = {}): ApplicantProfile {
  return mergeProfile(emptyProfile(), {
    name: "Ann",
    state: "FL",
    intent: "mortgage_protection",
    coverage_on_whom: "primary",
    age: 40,
    loan_balance: 200000,
    height_ft_in: "5'6\"",
    weight_lb: 140,
    tobacco_answered: true,
    tobacco_products: ["None"],
    ...extra,
  });
}

test("STEP_META has steps 0-8", () => {
  for (let i = 0; i <= 8; i++) assert.ok(STEP_META[i as keyof typeof STEP_META]);
});

test("blocked process stays at step 0", () => {
  const p = computeProcess(emptyProfile(), "NO-MTG");
  assert.equal(p.step, 0);
  assert.equal(p.blocked, true);
});

test("gates advance 0 through 8", () => {
  assert.equal(computeProcess(emptyProfile()).step, 0);
  let p = mergeProfile(emptyProfile(), { name: "Ann", state: "TX" });
  assert.equal(computeProcess(p).step, 1);
  p = mergeProfile(p, { intent: "mortgage_protection", coverage_on_whom: "primary" });
  assert.equal(computeProcess(p).step, 2);
  p = mergeProfile(p, { age: 40, loan_balance: 100000 });
  assert.equal(computeProcess(p).step, 3);
  p = mergeProfile(p, { height_ft_in: "5'8\"", weight_lb: 150, tobacco_answered: true });
  assert.equal(computeProcess(p).step, 4);
  p = mergeProfile(p, { diseases_complete: true, beneficiary_relationship: "self" });
  assert.equal(computeProcess(p).step, 5);
  p = mergeProfile(p, { annual_income: 85000 });
  assert.ok(computeProcess(p).step >= 6);
  p = mergeProfile(p, {
    decision_result: {
      offer_family: "si_level",
      reasons: ["x"],
      drivers: [],
      suggested_next_step: "agent",
    },
    carrier_shortlist: ["A"],
    agent_handoff_ack: true,
  });
  assert.equal(computeProcess(p).step, 8);
});

test("co-borrower needs spouse at step 5", () => {
  const p = base({
    co_borrower_flag: true,
    diseases_complete: true,
    coverage_on_whom: "both",
  });
  const proc = computeProcess(p);
  assert.equal(proc.step, 5);
  assert.ok(missingRequired(p, 5).includes("spouse_age_sex"));
  assert.ok(missingRequired(p, 5).includes("spouse_annual_income"));
  assert.ok(missingRequired(p, 5).includes("annual_income"));
});

test("missingRequired per step", () => {
  assert.ok(missingRequired(emptyProfile(), 0).includes("state"));
  assert.ok(missingRequired(emptyProfile(), 1).includes("intent"));
  assert.ok(missingRequired(emptyProfile(), 2).includes("loan_balance"));
  assert.ok(missingRequired(emptyProfile(), 3).includes("height_ft_in"));
  assert.ok(missingRequired(emptyProfile(), 4).some((m) => m.startsWith("diseases")));
  assert.ok(missingRequired(emptyProfile(), 5).includes("annual_income"));
  assert.ok(missingRequired(emptyProfile(), 5).includes("beneficiary_relationship"));
  assert.ok(missingRequired(emptyProfile(), 6).includes("decision_result"));
  assert.ok(missingRequired(emptyProfile(), 7).includes("carrier_shortlist"));
  assert.ok(missingRequired(emptyProfile(), 8).includes("agent_handoff_ack"));
});

test("stop paths", () => {
  assert.equal(detectStopPath("I rent"), "NO-MTG");
  assert.equal(detectStopPath("I am a renter"), "NO-MTG");
  assert.equal(detectStopPath("I want to refinance my rate"), "WR-LOAN");
  assert.equal(detectStopPath("I need health insurance"), "WR-HEALTH");
  assert.equal(detectStopPath("do not call"), "DNC");
  assert.equal(detectStopPath("hello"), null);
});

test("emergency", () => {
  assert.equal(detectEmergency("chest pain now"), true);
  assert.equal(detectEmergency("I cannot breathe"), true);
  assert.equal(detectEmergency("I feel fine"), false);
});

test("WR-LOAN skipped when they want protect", () => {
  assert.equal(detectStopPath("refinance to protect the loan"), null);
});
