import { expect, type APIRequestContext, type Page } from "@playwright/test";

export type CaseJson = {
  caseId: string;
  status: string;
  stopPath?: string | null;
  process: { step: number; missingRequired: string[]; blocked?: boolean };
  profile: Record<string, unknown>;
  messages: { role: string; content: string }[];
};

export async function createCase(request: APIRequestContext): Promise<CaseJson> {
  const res = await request.post("/api/mortgage/case");
  const body = await res.json();
  expect(res.ok(), body.error || JSON.stringify(body)).toBeTruthy();
  expect(body.caseId).toBeTruthy();
  return body as CaseJson;
}

export async function sendChat(
  request: APIRequestContext,
  caseId: string,
  message: string
): Promise<CaseJson> {
  const res = await request.post("/api/mortgage/chat", {
    data: { caseId, message },
  });
  const body = await res.json();
  expect(res.ok(), body.error || JSON.stringify(body)).toBeTruthy();
  return body as CaseJson;
}

export async function patchProfile(
  request: APIRequestContext,
  caseId: string,
  patch: Record<string, unknown>
): Promise<CaseJson> {
  const res = await request.patch("/api/mortgage/profile", {
    data: { caseId, patch },
  });
  const body = await res.json();
  expect(res.ok(), body.error || JSON.stringify(body)).toBeTruthy();
  return body as CaseJson;
}

export async function sendMany(
  request: APIRequestContext,
  caseId: string,
  messages: string[]
): Promise<CaseJson> {
  let last: CaseJson | undefined;
  for (const message of messages) {
    last = await sendChat(request, caseId, message);
  }
  expect(last).toBeTruthy();
  return last!;
}

/** Primary-insured script. After diseases, step 5 asks income. */
export const STEP_SCRIPT = {
  name: "My name is Pat Lee",
  state: "Florida",
  intent: "I want mortgage protection on me only",
  age: "I am 40 years old",
  loan: "loan balance 180k usd, 20 years left",
  build: `5'8" 160 lb non-smoker`,
  diseases: "none of those",
  income: "my annual income is 85k",
  spouseIncome: "spouse income is 40k",
  handoff: "ok",
};

/** Messages that land a primary-insured case on step 4 (disease interview). */
export const TO_STEP_4 = [
  STEP_SCRIPT.name,
  STEP_SCRIPT.state,
  STEP_SCRIPT.intent,
  STEP_SCRIPT.age,
  STEP_SCRIPT.loan,
  STEP_SCRIPT.build,
];

export async function getCase(request: APIRequestContext, caseId: string): Promise<CaseJson> {
  const res = await request.get(`/api/mortgage/case?id=${caseId}`);
  const body = await res.json();
  expect(res.ok(), body.error || JSON.stringify(body)).toBeTruthy();
  return body as CaseJson;
}

export function profileRow(page: Page, label: string) {
  return page.locator("div.flex.justify-between").filter({
    has: page.locator("span.text-slate-400").filter({ hasText: new RegExp(`(?:R|S|O)\\s+${label}$`) }),
  });
}

export async function openCaseOnStep(page: Page, caseId: string) {
  await page.goto(`/mortgage?case=${caseId}`, { waitUntil: "domcontentloaded" });
  await expect(page.getByTestId("process-current")).toBeVisible({ timeout: 45_000 });
}

export async function waitForChatReady(page: Page) {
  await page.addInitScript(() => {
    sessionStorage.removeItem("mortgageCaseId");
    sessionStorage.removeItem("mortgageCaseBooting");
  });
  await page.goto("/mortgage", { waitUntil: "domcontentloaded" });
  await expect(page.getByLabel("Chat message")).toBeEnabled({ timeout: 45_000 });
  await expect(page.getByTestId("process-current")).toBeVisible();
}

export async function sendUi(page: Page, message: string, opts?: { allowDisabled?: boolean }) {
  const box = page.getByLabel("Chat message");
  await expect(box).toBeEnabled();
  await box.fill(message);
  const wait = page.waitForResponse(
    (r) => r.url().includes("/api/mortgage/chat") && r.request().method() === "POST",
    { timeout: 45_000 }
  );
  await page.getByRole("button", { name: "Send" }).click();
  const res = await wait;
  expect(res.ok(), await res.text()).toBeTruthy();
  if (!opts?.allowDisabled) {
    await expect(box).toBeEnabled({ timeout: 45_000 });
  }
}
