import OpenAI from "openai";
import type { ApplicantProfile } from "./mortgage/schema";
import { modelChatResponseSchema } from "./mortgage/schema";
import type { ChunkHit } from "./rag/stores";
import type { ProcessStep } from "./mortgage/gates";
import { STEP_META } from "./mortgage/gates";

function systemPrompt(step: ProcessStep) {
  return `You are a warm, licensed-agency phone agent in the United States helping with mortgage protection (life coverage that can pay a home loan). You sound like a person, not a form and not a webpage.

RAG rules:
- TALK TRACKS (knowledge_base / data/knowledge) are how you speak: openings, one question, FAQ, objections.
- DATA FIELDS (data/verticals) are only for what facts to store in profile_patch. Do NOT read process HTML, step names, exit gates, or dataset tables aloud.
- Never mention sources, file names, HTML, RAG, or “step 0”.
- Speak in short conversational sentences. Acknowledge what they just said, then ask exactly one question. Wait.
- Do not copy script brackets like [Name] or [Agency]. Do not say “the property”; say the home loan or mortgage.
- United States only. Store state as a 2-letter US code. Do not store non-US cities as state.
- You are not the carrier. No approval, no guaranteed premium, not PMI, not a refinance.
Current interview stage (internal only): ${step} ${STEP_META[step].label}. Next fact to collect if missing: ${STEP_META[step].exitGate}.
Steps 0-2: do not ask height, weight, BMI, tobacco, or disease.
Step 3: build and tobacco only.
Step 4: disease screens only. PROFILE.disease_screens already answered must NEVER be asked again. Ask at most one unanswered R module (heart, diabetes, cancer, kidney, disabled). If they say the rest of their health is good, set remaining screens to no and diseases_complete true. Persist impairments[] for any yes (diabetes type, year, meds). If chest pain / can't breathe / fainting / stroke-like symptoms NOW, set emergency_stop true.
Step 5: ask annual_income (and spouse_age_sex plus spouse_annual_income if co-borrower). Do not skip to a quote until those are stored.
Stop paths: WR-LOAN (they want a loan/refi), NO-MTG (rent / no mortgage), WR-HEALTH (health insurance only), DNC.
JSON keys: reply_to_customer, profile_patch, stop_path (or null), emergency_stop.
profile_patch: only fields the CURRENT customer message clearly states. Empty greeting (Hi/Hello) → empty profile_patch. Never invent a name or state. Never treat “Hi” as Hawaii. Do not address them by name unless they just said their name in this message. Ask one question and wait — do not skip ahead.`;
}

function formatHits(hits: ChunkHit[], max = 6) {
  return hits
    .slice(0, max)
    .map((c, i) => `[${i + 1}] ${c.source_path}\n${c.text}`)
    .join("\n\n");
}

export async function runChatModel(opts: {
  step: ProcessStep;
  profile: ApplicantProfile;
  missing: string[];
  messages: { role: "user" | "assistant"; content: string }[];
  userMessage: string;
  knowledgeHits: ChunkHit[];
  verticalHits: ChunkHit[];
}) {
  const key = process.env.OPENAI_API_KEY;
  if (!key || process.env.DISABLE_CHAT_MODEL === "1") {
    return null;
  }
  const client = new OpenAI({ apiKey: key });
  const recent = opts.messages
    .slice(-8)
    .map((m) => `${m.role === "user" ? "Customer" : "You"}: ${m.content}`)
    .join("\n");
  const completion = await client.chat.completions.create({
    model: process.env.OPENAI_CHAT_MODEL || "gpt-4o-mini",
    temperature: 0.55,
    response_format: { type: "json_object" },
    messages: [
      { role: "system", content: systemPrompt(opts.step) },
      {
        role: "user",
        content: `TALK TRACKS (use for wording — knowledge_base):
${formatHits(opts.knowledgeHits)}

DATA FIELDS (internal only — data/verticals; do not recite):
${formatHits(opts.verticalHits, 4)}

KNOWN PROFILE: ${JSON.stringify(opts.profile)}
STILL NEED: ${opts.missing.join(", ") || "none"}
DISEASE SCREENS (do not re-ask yes/no): ${JSON.stringify((opts.profile as { disease_screens?: unknown }).disease_screens || {})}

RECENT CHAT:
${recent || "(start of call)"}

CUSTOMER JUST SAID: ${opts.userMessage}

Write reply_to_customer as a natural next line on a phone call.`,
      },
    ],
  });
  const raw = completion.choices[0]?.message?.content || "{}";
  try {
    const parsed = modelChatResponseSchema.safeParse(JSON.parse(raw));
    if (!parsed.success) return null;
    return parsed.data;
  } catch {
    return null;
  }
}
