import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { runChatModel } from "@/lib/openai";
import { retrieveRag } from "@/lib/rag/retrieve";
import {
  loadCase,
  payloadFromRow,
  profileIndex,
  serializeCase,
  syncCustomerFromProfile,
} from "@/lib/mortgage/caseService";
import { heuristicPatch, mergeProfile } from "@/lib/mortgage/extract";
import { nextDiseaseQuestion, healthGateComplete } from "@/lib/mortgage/health";
import { computeProcess, detectEmergency, detectStopPath, type ProcessStep } from "@/lib/mortgage/gates";
import { STUB_CARRIERS, stubDecision } from "@/lib/mortgage/decisionStub";
import { extractPersonName, isGreetingOnly, isNonUsLocation, isPlausibleName, parseUsState } from "@/lib/mortgage/usGeo";

function fallbackReply(step: ProcessStep, missing: string[], stop?: string | null, emergency?: boolean) {
  if (emergency) {
    return "Please seek emergency care now (call 911). We’ll pause this interview.";
  }
  if (stop === "NO-MTG") {
    return "Mortgage protection is for people with a home loan. If you rent or the loan is paid off, this product isn’t a fit. A licensed agent can still talk about other coverage if you want.";
  }
  if (stop === "WR-LOAN") {
    return "I can’t help with a new loan or refinance. I only cover mortgage protection insurance. A licensed agent can discuss that product if you still want it.";
  }
  if (stop === "WR-HEALTH") {
    return "This chat is mortgage protection, not health insurance. I can connect you with a licensed agent for the right product.";
  }
  if (stop === "DNC") {
    return "Understood — we won’t call. This chat is closed.";
  }
  const ask: Record<string, string> = {
    name_or_phone: "What’s your name, and a phone we can reach you on?",
    state: "Which U.S. state is the home loan in? Please use the state name or two-letter code (for example Texas or TX).",
    intent: "Are you looking to protect the mortgage (life insurance that can pay the loan), or something else?",
    coverage_on_whom: "Should coverage be on you, your spouse, or both people on the loan?",
    date_of_birth: "What’s your date of birth or age?",
    loan_balance: "About how much is still owed on the mortgage, and how many years are left?",
    height_ft_in: "What’s your height (for example 5'10\")?",
    weight_lb: "What’s your current weight in pounds?",
    tobacco: "Any tobacco or nicotine in the last 12 months?",
    diseases: "Any history of heart disease, diabetes, cancer, kidney disease, or disability? You can say none — I will only ask the groups we have not recorded yet.",
    spouse_age_sex: "What’s your spouse’s age (and sex if you’re comfortable sharing)?",
    spouse_annual_income: "About what is your spouse’s annual income?",
    annual_income: "About what is your annual household income from work (a round number is fine)?",
    beneficiary_relationship: "Who should be the beneficiary — spouse, children, or someone else?",
    decision_result: "I’ll outline an illustrative product family next (not a bind).",
    carrier_shortlist: "A licensed agent will shop appointed carriers. I’ll note a placeholder shortlist.",
    agent_handoff_ack: "A licensed agent will finish quoting, e-app, and issue. Reply “ok” to confirm the handoff.",
  };
  const first = missing[0];
  if (step === 8) return ask.agent_handoff_ack;
  if (step === 6) return "Based on what you shared, this is an illustrative underwriting path only — not an offer. A licensed agent must quote and bind.";
  if (first?.startsWith("diseases")) return ask.diseases;
  if (first && ask[first]) return ask[first];
  return "Thanks — anything else about the mortgage or who should be covered?";
}

function sanitizePatch(
  patch: Partial<import("@/lib/mortgage/schema").ApplicantProfile>,
  message: string,
  existingName?: string
) {
  if (isGreetingOnly(message)) return {};
  if (patch.state && !parseUsState(message) && !parseUsState(String(patch.state))) delete patch.state;
  if (patch.state && isGreetingOnly(message)) delete patch.state;
  if (patch.state && !parseUsState(message)) delete patch.state;
  if (patch.name && !extractPersonName(message) && !/my name is/i.test(message)) delete patch.name;
  if (patch.name && !isPlausibleName(String(patch.name))) delete patch.name;
  if (
    existingName &&
    patch.name &&
    existingName.split(/\s+/).length > String(patch.name).split(/\s+/).length
  ) {
    delete patch.name;
  }
  return patch;
}

export async function POST(req: Request) {
  const body = await req.json();
  const caseId = body.caseId as string;
  const userMessage = String(body.message || "").trim();
  if (!caseId || !userMessage) {
    return NextResponse.json({ error: "caseId and message required" }, { status: 400 });
  }

  const row = await loadCase(caseId);
  if (!row) return NextResponse.json({ error: "not found" }, { status: 404 });

  const lastUser = [...row.messages].reverse().find((m) => m.role === "user");
  if (
    lastUser &&
    lastUser.content === userMessage &&
    Date.now() - lastUser.createdAt.getTime() < 10000
  ) {
    return NextResponse.json(serializeCase(row));
  }

  let profile = payloadFromRow(row.profile);
  if (isGreetingOnly(userMessage) && profile.state === "HI") {
    const prior = row.messages.filter((m) => m.role === "user").map((m) => m.content);
    const saidRealState = prior.some((m) => parseUsState(m) && !isGreetingOnly(m));
    if (!saidRealState) {
      const next = { ...profile };
      delete next.state;
      profile = next;
    }
  }
  let stop = row.stopPath || detectStopPath(userMessage);
  const processBefore = computeProcess(profile, stop);
  const emergency =
    (processBefore.step === 4 && detectEmergency(userMessage)) || false;

  const lastAsstForExtract = [...row.messages].reverse().find((m) => m.role === "assistant");
  const rag = retrieveRag(userMessage, processBefore.step, processBefore.missingRequired);

  const model = await runChatModel({
    step: processBefore.step,
    profile,
    missing: processBefore.missingRequired,
    messages: row.messages.map((m) => ({
      role: m.role as "user" | "assistant",
      content: m.content,
    })),
    userMessage,
    knowledgeHits: rag.knowledge,
    verticalHits: rag.verticals,
  });

  if (model?.stop_path) stop = model.stop_path;
  if (model?.emergency_stop) {
    /* handled below */
  }
  const patch = sanitizePatch(
    {
      ...(isGreetingOnly(userMessage)
        ? {}
        : heuristicPatch(userMessage, {
            lastAssistant: lastAsstForExtract?.content,
            profile,
          })),
      ...(isGreetingOnly(userMessage) ? {} : model?.profile_patch || {}),
    } as Partial<import("@/lib/mortgage/schema").ApplicantProfile>,
    userMessage,
    profile.name
  );
  if (/^ok\b|handoff|licensed agent/i.test(userMessage) && processBefore.step >= 8) {
    patch.agent_handoff_ack = true;
  }
  profile = mergeProfile(profile, patch);
  if (profile.coverage_on_whom === "primary" && !profile.beneficiary_relationship) {
    profile = mergeProfile(profile, { beneficiary_relationship: "self" });
  }

  if (model?.emergency_stop || emergency) {
    stop = stop || "EMERGENCY";
  }

  let process = computeProcess(profile, stop && stop !== "EMERGENCY" ? stop : row.stopPath);

  if (!stop && process.step >= 6 && !profile.decision_result) {
    profile = mergeProfile(profile, { decision_result: stubDecision(profile) });
    process = computeProcess(profile);
  }
  if (!stop && process.step >= 7 && !profile.carrier_shortlist?.length) {
    profile = mergeProfile(profile, { carrier_shortlist: STUB_CARRIERS });
    process = computeProcess(profile);
  }

  const blocked = Boolean(stop);
  const emergencyNow = emergency || Boolean(model?.emergency_stop);
  const stepQuestion =
    process.step === 4 && !healthGateComplete(profile)
      ? nextDiseaseQuestion(profile)
      : fallbackReply(process.step, process.missingRequired, stop, emergencyNow);

  let reply = model?.reply_to_customer || stepQuestion;

  if (isGreetingOnly(userMessage) && !stop && !emergencyNow) {
    if (!profile.name && !profile.phone) {
      reply = "Hi — thanks for writing in. What’s your name?";
    } else if (!profile.state) {
      reply = "Hi again — which U.S. state is the mortgage in?";
    } else {
      reply = `Hi — I’ve still got your file. ${stepQuestion}`;
    }
  }

  if (isNonUsLocation(userMessage) && !profile.state) {
    reply =
      "This chat is only for U.S. mortgage protection. I can’t use a city or state outside the United States. Which U.S. state is the home loan in (for example Texas or TX)?";
  }
  reply = reply.replace(/\bthe property\b/gi, "the home loan").replace(/\bproperty in\b/gi, "home loan in");

  if (
    (process.step === 4 || processBefore.step === 4) &&
    !stop &&
    !emergencyNow &&
    !healthGateComplete(profile)
  ) {
    const nextQ = nextDiseaseQuestion(profile);
    const asksEarlierGate =
      /tobacco|nicotine|which u\.s\. state|what’s your name|what's your name|date of birth|how much is still owed|height|weight/i.test(
        reply
      );
    if (asksEarlierGate || lastAsstForExtract?.content.trim() === reply.trim()) {
      reply = isGreetingOnly(userMessage) && profile.state ? `Hi — I’ve still got your file. ${nextQ}` : nextQ;
    }
  }

  if (
    process.step === 5 &&
    !stop &&
    !emergencyNow &&
    process.missingRequired.length > 0
  ) {
    const incomeQ = fallbackReply(5, process.missingRequired, stop, emergencyNow);
    const asksWrong =
      /tobacco|nicotine|which u\.s\. state|disease|heart attack|diabetes|cancer/i.test(reply);
    if (asksWrong || lastAsstForExtract?.content.trim() === reply.trim() || isGreetingOnly(userMessage)) {
      reply = isGreetingOnly(userMessage) && profile.state ? `Hi — I’ve still got your file. ${incomeQ}` : incomeQ;
    }
  }

  if (lastAsstForExtract && lastAsstForExtract.content.trim() === reply.trim() && !stop && !emergencyNow) {
    reply = stepQuestion;
  }

  const citations = rag.knowledge.slice(0, 4).map((c) => ({
    id: c.id,
    title: c.title,
    source_path: c.source_path,
    score: Number(c.score.toFixed(4)),
    lane: "knowledge" as const,
  }));

  await prisma.$transaction([
    prisma.chatMessage.create({
      data: { caseId, role: "user", content: userMessage, createdAt: new Date() },
    }),
    prisma.chatMessage.create({
      data: {
        caseId,
        role: "assistant",
        content: reply,
        citationsJson: citations,
        createdAt: new Date(Date.now() + 1),
      },
    }),
    prisma.verticalProfile.update({ where: { caseId }, data: profileIndex(profile) }),
    prisma.insuranceCase.update({
      where: { id: caseId },
      data: {
        processStep: process.step,
        status: blocked ? "stopped" : process.step >= 8 && profile.agent_handoff_ack ? "handoff" : "open",
        stopPath: stop,
        blockedReason: stop,
      },
    }),
    prisma.customer.update({
      where: { id: row.customerId },
      data: syncCustomerFromProfile(profile),
    }),
  ]);

  const next = await loadCase(caseId);
  return NextResponse.json({
    ...serializeCase(next!),
    citations,
  });
}
