type LegacyName = {
  family?: string | null;
  given?: string | null;
  middle?: string | null;
};

type LegacyAddress = {
  in_care_of?: string | null;
  street?: string | null;
  unit_type?: string | null;
  unit_num?: string | null;
  city?: string | null;
  state?: string | null;
  zip?: string | null;
  province?: string | null;
  postal?: string | null;
  country?: string | null;
};

type LegacyApplicant = {
  a_number?: string | null;
  name?: LegacyName | null;
  other_names_used?: LegacyName[] | null;
  dob?: string | null;
  country_of_birth?: string | null;
  city_of_birth?: string | null;
  country_of_citizenship?: string | null;
  ssn?: string | null;
  sex?: string | null;
  marital_status?: string | null;
  mailing_address?: LegacyAddress | null;
  physical_address_same_as_mailing?: boolean | null;
  physical_address?: LegacyAddress | null;
  last_foreign_address?: LegacyAddress | null;
  phone?: string | null;
  email?: string | null;
  passport?: {
    number?: string | null;
    country_of_issuance?: string | null;
    expiration?: string | null;
  } | null;
  visa_at_last_entry?: {
    class?: string | null;
    number?: string | null;
    control_number?: string | null;
    issuing_post?: string | null;
    issue_date?: string | null;
    expiration?: string | null;
  } | null;
  height_ft?: string | null;
  height_in?: string | null;
  weight_lb?: string | null;
  eye_color?: string | null;
  hair_color?: string | null;
  race?: string[] | null;
  ethnicity?: string | null;
};

type LegacyPetitioner = {
  type?: string | null;
  legal_name?: string | null;
  trade_name?: string | null;
  fein?: string | null;
  naics_code?: string | null;
  business_type?: string | null;
  business_activity?: string | null;
  address?: LegacyAddress | null;
  phone?: string | null;
  email?: string | null;
  contact_person?: {
    family?: string | null;
    given?: string | null;
    title?: string | null;
  } | null;
  date_established?: string | null;
  ownership_structure?: string | null;
  gross_annual_income?: string | null;
  net_annual_income?: string | null;
  employees?: string | null;
};

type LegacyI140 = {
  receipt_number?: string | null;
  priority_date?: string | null;
  category?: string | null;
  preference_text?: string | null;
  approved?: boolean | null;
  approval_date?: string | null;
  perm_case_number?: string | null;
  perm_filed_date?: string | null;
  perm_expiration_date?: string | null;
  job_title?: string | null;
  soc_code?: string | null;
  soc_title?: string | null;
  prevailing_wage?: string | null;
  offered_wage?: string | null;
  nontechnical_description?: string | null;
  full_time?: boolean | null;
  permanent?: boolean | null;
};

type LegacyTravelHistoryEntry = {
  date_of_entry?: string | null;
  port_of_entry?: string | null;
  class_of_admission?: string | null;
  admit_until?: string | null;
  i94_number?: string | null;
  inspected?: boolean | null;
};

type LegacyCurrentStatus = {
  class?: string | null;
  expires?: string | null;
  most_recent_i797?:
    | {
        type?: string | null;
        receipt?: string | null;
        notice_date?: string | null;
        valid_from?: string | null;
        valid_to?: string | null;
      }
    | null;
};

type LegacyI20Entry = {
  sevis_id?: string | null;
  school?: string | null;
  program?: string | null;
  date_issued?: string | null;
  program_start?: string | null;
  program_end?: string | null;
  reason?: string | null;
};

type LegacyMarriage = {
  status?: string | null;
  spouse?:
    | (LegacyName & {
        dob?: string | null;
        country_of_birth?: string | null;
        a_number?: string | null;
      })
    | null;
  date_of_marriage?: string | null;
  place_of_marriage?: {
    city?: string | null;
    state?: string | null;
    country?: string | null;
  } | null;
  date_of_divorce?: string | null;
  place_of_divorce?: {
    city?: string | null;
    state?: string | null;
    country?: string | null;
  } | null;
};

type LegacyParent = {
  role?: string | null;
  family?: string | null;
  given?: string | null;
  middle?: string | null;
  dob?: string | null;
  country_of_birth?: string | null;
  city_of_residence?: string | null;
  country_of_residence?: string | null;
};

type LegacyDependent = {
  relationship?: string | null;
  filing_with_principal?: boolean | null;
  name?: LegacyName | null;
  dob?: string | null;
  country_of_birth?: string | null;
  city_of_birth?: string | null;
  a_number?: string | null;
  current_status?: string | null;
  in_us?: boolean | null;
  address_same_as_principal?: boolean | null;
};

type LegacyI94 = {
  number?: string | null;
  class?: string | null;
  admit_until?: string | null;
  date_of_entry?: string | null;
  port_of_entry?: string | null;
  name?: LegacyName | null;
};

type LegacyEligibilityAnswers = {
  ever_arrested?: boolean | null;
  ever_public_cash_assistance?: boolean | null;
  household_size?: string | number | null;
  household_assets_value?: string | null;
  other_yes_flags?: string[] | null;
};

type LegacyMeta = {
  build_at?: string | null;
  source_folder?: string | null;
  missing_fields?: string[] | null;
  flags?: string[] | null;
};

export type LegacyEmploymentAdjustmentCaseData = {
  case_id?: string | null;
  project_type?: string | null;
  source_folder?: string | null;
  applicant?: LegacyApplicant | null;
  attorney?: Record<string, unknown> | null;
  petitioner?: LegacyPetitioner | null;
  i140?: LegacyI140 | null;
  travel_history?: LegacyTravelHistoryEntry[] | null;
  current_status?: LegacyCurrentStatus | null;
  i20_history?: LegacyI20Entry[] | null;
  marriages?: LegacyMarriage[] | null;
  parents?: LegacyParent[] | null;
  dependents?: LegacyDependent[] | null;
  i94?: LegacyI94 | null;
  eligibility_answers?: LegacyEligibilityAnswers | null;
  meta?: LegacyMeta | null;
};

export type LegacyEmploymentAdjustmentBuildReport = {
  case_id?: string | null;
  project?: string | null;
  forms?: Record<
    string,
    {
      wrote?: number | null;
      skipped?: number | null;
      unknown?: string[] | null;
    }
  > | null;
  missing?: string[] | null;
  errors?: string[] | null;
};

export type LegacyEmploymentAdjustmentDocsManifest = {
  title?: string | null;
  note?: string | null;
  sections?: Array<{
    label?: string | null;
    file?: string | null;
  }> | null;
};

export type LegacyEmploymentAdjustmentArtifacts = {
  caseData: LegacyEmploymentAdjustmentCaseData | null;
  buildReport: LegacyEmploymentAdjustmentBuildReport | null;
  docsManifest: LegacyEmploymentAdjustmentDocsManifest | null;
};

export type LegacyEmploymentAdjustmentKnowledgeFact = {
  factKey: string;
  label: string;
  value: string;
  confidence: number;
  evidence: string;
  sourceTitles: string[];
  scope: "profile" | "knowledge";
};

export type LegacyEmploymentAdjustmentKnowledge = {
  summaryText: string;
  profileFacts: LegacyEmploymentAdjustmentKnowledgeFact[];
  knowledgeFacts: LegacyEmploymentAdjustmentKnowledgeFact[];
  unresolvedTopics: string[];
  sourceTitles: string[];
};

export type LegacyEmploymentAdjustmentFactCandidate = {
  fieldKey: string;
  label: string;
  rawValue: string;
  dataType: "string" | "date" | "number" | "boolean";
  confidence: number;
  evidenceExcerpt: string;
  requiresHumanConfirmation?: boolean;
};

function normalizeWhitespace(value: unknown) {
  return String(value ?? "")
    .replace(/\s+/g, " ")
    .trim();
}

function normalizeLegacyScalar(value: unknown) {
  const normalized = normalizeWhitespace(value);
  if (!normalized) {
    return null;
  }

  if (/^(none|n\/a|na|null|unknown|not available)$/i.test(normalized)) {
    return null;
  }

  return normalized;
}

function normalizeLegacyBoolean(value: unknown) {
  if (typeof value === "boolean") {
    return value ? "true" : "false";
  }

  const normalized = normalizeLegacyScalar(value);
  if (!normalized) {
    return null;
  }

  if (/^(yes|true|y|1)$/i.test(normalized)) {
    return "true";
  }

  if (/^(no|false|n|0)$/i.test(normalized)) {
    return "false";
  }

  return null;
}

function normalizeLegacyDate(value: unknown) {
  const normalized = normalizeLegacyScalar(value);
  if (!normalized) {
    return null;
  }

  if (/^\d{2}\/\d{2}\/\d{4}$/.test(normalized)) {
    return normalized;
  }

  if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) {
    const [year, month, day] = normalized.split("-");
    return `${month}/${day}/${year}`;
  }

  return normalized;
}

function normalizeLegacyNumberString(value: unknown) {
  const normalized = normalizeLegacyScalar(value);
  if (!normalized) {
    return null;
  }

  const digits = normalized.replace(/[^\d.]/g, "");
  return digits || normalized;
}

function buildNameValue(name: LegacyName | null | undefined) {
  const parts = [
    normalizeLegacyScalar(name?.given),
    normalizeLegacyScalar(name?.middle),
    normalizeLegacyScalar(name?.family),
  ].filter(Boolean);

  return parts.length ? parts.join(" ") : null;
}

function buildAddressLine1(address: LegacyAddress | null | undefined) {
  return normalizeLegacyScalar(address?.street);
}

function buildAddressLine2(address: LegacyAddress | null | undefined) {
  const unitType = normalizeLegacyScalar(address?.unit_type);
  const unitNum = normalizeLegacyScalar(address?.unit_num);
  if (!unitType && !unitNum) {
    return null;
  }
  return [unitType, unitNum].filter(Boolean).join(" ");
}

function buildAddressLabel(address: LegacyAddress | null | undefined) {
  const parts = [
    normalizeLegacyScalar(address?.street),
    normalizeLegacyScalar(address?.unit_type),
    normalizeLegacyScalar(address?.unit_num),
    normalizeLegacyScalar(address?.city),
    normalizeLegacyScalar(address?.state),
    normalizeLegacyScalar(address?.zip),
    normalizeLegacyScalar(address?.province),
    normalizeLegacyScalar(address?.postal),
    normalizeLegacyScalar(address?.country),
  ].filter(Boolean);
  return parts.length ? parts.join(", ") : null;
}

function latestTravelEntry(caseData: LegacyEmploymentAdjustmentCaseData) {
  const entries = Array.isArray(caseData.travel_history) ? caseData.travel_history : [];
  return entries.length ? entries[entries.length - 1] ?? null : null;
}

function latestI20Entry(caseData: LegacyEmploymentAdjustmentCaseData) {
  const entries = Array.isArray(caseData.i20_history) ? caseData.i20_history : [];
  if (!entries.length) {
    return null;
  }

  return [...entries].sort((left, right) => {
    const leftDate = Date.parse(String(left.date_issued ?? left.program_end ?? ""));
    const rightDate = Date.parse(String(right.date_issued ?? right.program_end ?? ""));
    return (Number.isNaN(rightDate) ? 0 : rightDate) - (Number.isNaN(leftDate) ? 0 : leftDate);
  })[0] ?? null;
}

function currentMarriage(caseData: LegacyEmploymentAdjustmentCaseData) {
  return (caseData.marriages ?? []).find((marriage) =>
    /^current$/i.test(normalizeWhitespace(marriage?.status)),
  ) ?? null;
}

function firstChildDependent(caseData: LegacyEmploymentAdjustmentCaseData) {
  return (caseData.dependents ?? []).find((dependent) =>
    /child|son|daughter/i.test(normalizeWhitespace(dependent?.relationship)),
  ) ?? null;
}

function normalizeEmploymentBasedCategory(category: string | null | undefined) {
  const normalized = normalizeWhitespace(category).toLowerCase();
  if (!normalized) {
    return null;
  }

  if (normalized.includes("eb3") && normalized.includes("skilled")) {
    return "skilled_worker";
  }
  if (normalized.includes("professional")) {
    return "professional";
  }
  if (normalized.includes("other")) {
    return "other_worker";
  }
  if (normalized.includes("advanced") || normalized.includes("exceptional") || normalized.includes("eb2")) {
    return "advanced_degree";
  }

  return normalized;
}

function normalizeMaritalStatus(value: string | null | undefined) {
  const normalized = normalizeWhitespace(value).toLowerCase();
  if (!normalized) {
    return null;
  }

  if (normalized === "single" || normalized === "never married") {
    return "Single, Never Married";
  }
  if (normalized === "married") {
    return "Married";
  }
  if (normalized === "divorced") {
    return "Divorced";
  }
  if (normalized === "widowed") {
    return "Widowed";
  }
  if (normalized.includes("annul")) {
    return "Marriage Annulled";
  }
  if (normalized.includes("separated")) {
    return "Legally Separated";
  }

  return normalizeLegacyScalar(value);
}

function normalizeEyeOrHairColor(value: string | null | undefined) {
  const normalized = normalizeWhitespace(value).toLowerCase();
  if (!normalized) {
    return null;
  }

  const title = `${normalized.charAt(0).toUpperCase()}${normalized.slice(1)}`;
  if (title === "Bald") {
    return "Bald (No hair)";
  }
  if (title === "Other" || title === "Unknown") {
    return "Unknown / Other";
  }
  return title;
}

function formatMissingFieldPath(path: string) {
  return normalizeWhitespace(
    path
      .replace(/\[\*\]/g, " entries")
      .replace(/\[(\d+)\]/g, " $1 ")
      .replace(/[._]/g, " "),
  );
}

function createFact(
  target: LegacyEmploymentAdjustmentKnowledgeFact[],
  scope: "profile" | "knowledge",
  factKey: string,
  label: string,
  value: string | null,
  sourceTitle: string,
  confidence = 0.97,
) {
  const normalizedValue = normalizeLegacyScalar(value);
  if (!normalizedValue) {
    return;
  }

  target.push({
    factKey,
    label,
    value: normalizedValue,
    confidence,
    evidence: `${label}: ${normalizedValue}`.slice(0, 255),
    sourceTitles: [sourceTitle],
    scope,
  });
}

function safeJsonParse<T>(value: string): T | null {
  try {
    return JSON.parse(value) as T;
  } catch {
    return null;
  }
}

function looksLikeLegacyCaseData(parsed: unknown): parsed is LegacyEmploymentAdjustmentCaseData {
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
    return false;
  }

  const candidate = parsed as Record<string, unknown>;
  return (
    normalizeWhitespace(candidate.project_type).toLowerCase() === "employment_aos" &&
    typeof candidate.applicant === "object" &&
    !Array.isArray(candidate.applicant)
  );
}

function looksLikeLegacyBuildReport(parsed: unknown): parsed is LegacyEmploymentAdjustmentBuildReport {
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
    return false;
  }

  const candidate = parsed as Record<string, unknown>;
  return (
    typeof candidate.forms === "object" &&
    !Array.isArray(candidate.forms) &&
    Array.isArray(candidate.missing)
  );
}

function looksLikeLegacyDocsManifest(parsed: unknown): parsed is LegacyEmploymentAdjustmentDocsManifest {
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
    return false;
  }

  const candidate = parsed as Record<string, unknown>;
  return Array.isArray(candidate.sections);
}

export function parseLegacyEmploymentAdjustmentCaseData(
  text: string | null | undefined,
): LegacyEmploymentAdjustmentCaseData | null {
  const parsed = safeJsonParse<unknown>(String(text ?? "").trim());
  return looksLikeLegacyCaseData(parsed) ? parsed : null;
}

export function parseLegacyEmploymentAdjustmentBuildReport(
  text: string | null | undefined,
): LegacyEmploymentAdjustmentBuildReport | null {
  const parsed = safeJsonParse<unknown>(String(text ?? "").trim());
  return looksLikeLegacyBuildReport(parsed) ? parsed : null;
}

export function parseLegacyEmploymentAdjustmentDocsManifest(
  text: string | null | undefined,
): LegacyEmploymentAdjustmentDocsManifest | null {
  const parsed = safeJsonParse<unknown>(String(text ?? "").trim());
  return looksLikeLegacyDocsManifest(parsed) ? parsed : null;
}

export function extractLegacyEmploymentAdjustmentArtifactsFromDocuments(
  documents: Array<{ title: string; extracted_text: string | null }>,
): LegacyEmploymentAdjustmentArtifacts {
  let caseData: LegacyEmploymentAdjustmentCaseData | null = null;
  let buildReport: LegacyEmploymentAdjustmentBuildReport | null = null;
  let docsManifest: LegacyEmploymentAdjustmentDocsManifest | null = null;

  for (const document of documents) {
    const normalizedTitle = normalizeWhitespace(document.title).toLowerCase();
    const text = String(document.extracted_text ?? "").trim();

    if (!text) {
      continue;
    }

    if (!caseData && (normalizedTitle.includes("case_data.json") || text.includes('"project_type": "employment_aos"'))) {
      caseData = parseLegacyEmploymentAdjustmentCaseData(text);
    }

    if (
      !buildReport &&
      (normalizedTitle.includes("build_report.json") || (text.includes('"forms"') && text.includes('"missing"')))
    ) {
      buildReport = parseLegacyEmploymentAdjustmentBuildReport(text);
    }

    if (
      !docsManifest &&
      (normalizedTitle.includes("docs_manifest.json") || (text.includes('"sections"') && text.includes('"file"')))
    ) {
      docsManifest = parseLegacyEmploymentAdjustmentDocsManifest(text);
    }
  }

  return {
    caseData,
    buildReport,
    docsManifest,
  };
}

export function buildLegacyEmploymentAdjustmentKnowledge(
  artifacts: LegacyEmploymentAdjustmentArtifacts | null | undefined,
): LegacyEmploymentAdjustmentKnowledge | null {
  if (!artifacts?.caseData) {
    return null;
  }

  const caseData = artifacts.caseData;
  const caseDataTitle = `Legacy employment AOS case data${caseData.case_id ? ` • ${caseData.case_id}` : ""}`;
  const buildReportTitle = `Legacy employment AOS build report${caseData.case_id ? ` • ${caseData.case_id}` : ""}`;
  const manifestTitle = `Legacy employment AOS docs manifest${caseData.case_id ? ` • ${caseData.case_id}` : ""}`;

  const profileFacts: LegacyEmploymentAdjustmentKnowledgeFact[] = [];
  const knowledgeFacts: LegacyEmploymentAdjustmentKnowledgeFact[] = [];

  createFact(profileFacts, "profile", "client_first_name", "Applicant given name", caseData.applicant?.name?.given ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_middle_name", "Applicant middle name", caseData.applicant?.name?.middle ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_last_name", "Applicant family name", caseData.applicant?.name?.family ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_date_of_birth", "Applicant date of birth", normalizeLegacyDate(caseData.applicant?.dob), caseDataTitle);
  createFact(profileFacts, "profile", "client_birth_city", "Applicant city of birth", caseData.applicant?.city_of_birth ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_birth_country", "Applicant country of birth", caseData.applicant?.country_of_birth ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_country_of_citizenship", "Applicant country of citizenship", caseData.applicant?.country_of_citizenship ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_gender", "Applicant sex", caseData.applicant?.sex ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_marital_status", "Applicant marital status", normalizeMaritalStatus(caseData.applicant?.marital_status), caseDataTitle);
  createFact(profileFacts, "profile", "client_phone", "Applicant phone", caseData.applicant?.phone ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_email", "Applicant email", caseData.applicant?.email ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_alien_number", "Applicant A-number", caseData.applicant?.a_number ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_ssn", "Applicant Social Security number", caseData.applicant?.ssn ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "passport_number", "Passport number", caseData.applicant?.passport?.number ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_passport_issuing_country", "Passport issuing country", caseData.applicant?.passport?.country_of_issuance ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_passport_expiration_date", "Passport expiration date", normalizeLegacyDate(caseData.applicant?.passport?.expiration), caseDataTitle);
  createFact(profileFacts, "profile", "client_visa_number", "Visa number at last entry", caseData.applicant?.visa_at_last_entry?.number ?? null, caseDataTitle);

  const latestTravel = latestTravelEntry(caseData);
  createFact(profileFacts, "profile", "client_i94_number", "Most recent I-94 number", latestTravel?.i94_number ?? caseData.i94?.number ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_class_of_admission", "Class of admission", latestTravel?.class_of_admission ?? caseData.i94?.class ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_last_arrival_date", "Last arrival date", normalizeLegacyDate(latestTravel?.date_of_entry ?? caseData.i94?.date_of_entry), caseDataTitle);
  createFact(profileFacts, "profile", "client_authorized_stay_until", "Authorized stay until", normalizeLegacyDate(latestTravel?.admit_until ?? caseData.i94?.admit_until), caseDataTitle);
  createFact(profileFacts, "profile", "client_current_immigration_status", "Current immigration status", caseData.current_status?.class ?? null, caseDataTitle);

  createFact(profileFacts, "profile", "client_current_address_line1", "Current mailing street", buildAddressLine1(caseData.applicant?.mailing_address), caseDataTitle);
  createFact(profileFacts, "profile", "client_current_address_line2", "Current mailing unit", buildAddressLine2(caseData.applicant?.mailing_address), caseDataTitle);
  createFact(profileFacts, "profile", "client_current_city", "Current mailing city", caseData.applicant?.mailing_address?.city ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_current_state", "Current mailing state", caseData.applicant?.mailing_address?.state ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_current_zip_code", "Current mailing ZIP code", caseData.applicant?.mailing_address?.zip ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_current_country", "Current mailing country", caseData.applicant?.mailing_address?.country ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_foreign_address_line1", "Most recent foreign street", buildAddressLine1(caseData.applicant?.last_foreign_address), caseDataTitle);
  createFact(profileFacts, "profile", "client_foreign_city", "Most recent foreign city", caseData.applicant?.last_foreign_address?.city ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_foreign_province", "Most recent foreign province", caseData.applicant?.last_foreign_address?.province ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_foreign_postal_code", "Most recent foreign postal code", caseData.applicant?.last_foreign_address?.postal ?? null, caseDataTitle);
  createFact(profileFacts, "profile", "client_foreign_country", "Most recent foreign country", caseData.applicant?.last_foreign_address?.country ?? null, caseDataTitle);

  createFact(knowledgeFacts, "knowledge", "i140_receipt_number", "I-140 receipt number", caseData.i140?.receipt_number ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "i140_priority_date", "I-140 priority date", normalizeLegacyDate(caseData.i140?.priority_date), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "i140_category", "I-140 preference category", caseData.i140?.category ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "perm_case_number", "PERM case number", caseData.i140?.perm_case_number ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "job_title", "Offered job title", caseData.i140?.job_title ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "annual_salary", "Offered wage", caseData.i140?.offered_wage ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "employer_name", "Petitioner / employer legal name", caseData.petitioner?.legal_name ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "sponsor_fein", "Petitioner FEIN", caseData.petitioner?.fein ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "sponsor_contact_name", "Petitioner contact", buildNameValue({
    given: caseData.petitioner?.contact_person?.given,
    family: caseData.petitioner?.contact_person?.family,
    middle: caseData.petitioner?.contact_person?.title,
  }), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "sponsor_phone", "Petitioner phone", caseData.petitioner?.phone ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "sponsor_email", "Petitioner email", caseData.petitioner?.email ?? null, caseDataTitle);

  const parent1 = (caseData.parents ?? []).find((parent) => /father/i.test(normalizeWhitespace(parent.role)));
  const parent2 = (caseData.parents ?? []).find((parent) => /mother/i.test(normalizeWhitespace(parent.role)));
  createFact(knowledgeFacts, "knowledge", "parent_1_full_name", "Parent 1 full name", buildNameValue({
    given: parent1?.given,
    middle: parent1?.middle,
    family: parent1?.family,
  }), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "parent_1_date_of_birth", "Parent 1 date of birth", normalizeLegacyDate(parent1?.dob), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "parent_1_country_of_birth", "Parent 1 country of birth", parent1?.country_of_birth ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "parent_2_full_name", "Parent 2 full name", buildNameValue({
    given: parent2?.given,
    middle: parent2?.middle,
    family: parent2?.family,
  }), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "parent_2_date_of_birth", "Parent 2 date of birth", normalizeLegacyDate(parent2?.dob), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "parent_2_country_of_birth", "Parent 2 country of birth", parent2?.country_of_birth ?? null, caseDataTitle);

  const marriage = currentMarriage(caseData);
  const child = firstChildDependent(caseData);
  createFact(knowledgeFacts, "knowledge", "spouse_full_name", "Current spouse full name", buildNameValue(marriage?.spouse), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "spouse_date_of_birth", "Current spouse date of birth", normalizeLegacyDate(marriage?.spouse?.dob), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "spouse_country_of_birth", "Current spouse country of birth", marriage?.spouse?.country_of_birth ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "marriage_date", "Date of current marriage", normalizeLegacyDate(marriage?.date_of_marriage), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "marriage_country", "Country of current marriage", marriage?.place_of_marriage?.country ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "number_of_children", "Number of dependent children", String((caseData.dependents ?? []).filter((dependent) => /child|son|daughter/i.test(normalizeWhitespace(dependent.relationship))).length), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "child_1_full_name", "First child full name", buildNameValue(child?.name), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "child_1_date_of_birth", "First child date of birth", normalizeLegacyDate(child?.dob), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "child_1_country_of_birth", "First child country of birth", child?.country_of_birth ?? null, caseDataTitle);

  createFact(knowledgeFacts, "knowledge", "height_feet", "Height feet", caseData.applicant?.height_ft ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "height_inches", "Height inches", caseData.applicant?.height_in ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "weight_pounds", "Weight pounds", caseData.applicant?.weight_lb ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "eye_color", "Eye color", normalizeEyeOrHairColor(caseData.applicant?.eye_color), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "hair_color", "Hair color", normalizeEyeOrHairColor(caseData.applicant?.hair_color), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "client_has_been_arrested", "Ever arrested", normalizeLegacyBoolean(caseData.eligibility_answers?.ever_arrested), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "client_ever_public_cash_assistance", "Ever received public cash assistance", normalizeLegacyBoolean(caseData.eligibility_answers?.ever_public_cash_assistance), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "household_size", "Public charge household size", normalizeLegacyNumberString(caseData.eligibility_answers?.household_size), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "household_assets_value", "Public charge household assets value", caseData.eligibility_answers?.household_assets_value ?? null, caseDataTitle);

  const i20 = latestI20Entry(caseData);
  createFact(knowledgeFacts, "knowledge", "current_school_name", "Most recent school", i20?.school ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "current_school_program", "Most recent school program", i20?.program ?? null, caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "current_school_start_date", "Most recent school start date", normalizeLegacyDate(i20?.program_start), caseDataTitle);
  createFact(knowledgeFacts, "knowledge", "current_school_end_date", "Most recent school end date", normalizeLegacyDate(i20?.program_end), caseDataTitle);

  if (artifacts.docsManifest?.title) {
    createFact(knowledgeFacts, "knowledge", "supporting_docs_manifest_title", "Supporting documents manifest", artifacts.docsManifest.title, manifestTitle, 0.92);
  }

  for (const [index, section] of (artifacts.docsManifest?.sections ?? []).slice(0, 12).entries()) {
    createFact(
      knowledgeFacts,
      "knowledge",
      `supporting_doc_${index + 1}`,
      `Supporting document ${index + 1}`,
      section.label ?? section.file ?? null,
      manifestTitle,
      0.91,
    );
  }

  const unresolvedTopics = Array.from(
    new Set(
      [
        ...((artifacts.buildReport?.missing ?? []).map((item) => formatMissingFieldPath(String(item)))),
        ...((caseData.meta?.missing_fields ?? []).map((item) => formatMissingFieldPath(String(item)))),
      ].filter(Boolean),
    ),
  ).slice(0, 24);

  const sourceTitles = Array.from(
    new Set([
      caseDataTitle,
      artifacts.buildReport ? buildReportTitle : "",
      artifacts.docsManifest ? manifestTitle : "",
    ].filter(Boolean)),
  );

  const applicantName = buildNameValue(caseData.applicant?.name);
  const petitionerName = normalizeLegacyScalar(caseData.petitioner?.legal_name);
  const summaryParts = [
    applicantName ? `Legacy employment-based adjustment export available for ${applicantName}.` : "Legacy employment-based adjustment export available.",
    petitionerName ? `Sponsor/petitioner: ${petitionerName}.` : null,
    caseData.i140?.category ? `Preference category: ${caseData.i140.category}.` : null,
    latestTravel?.date_of_entry ? `Most recent documented entry: ${normalizeLegacyDate(latestTravel.date_of_entry)}.` : null,
    artifacts.docsManifest?.sections?.length ? `Supporting docs manifest lists ${artifacts.docsManifest.sections.length} item(s).` : null,
    unresolvedTopics.length ? `Legacy export still flags ${unresolvedTopics.length} unresolved topic(s).` : null,
  ].filter(Boolean);

  return {
    summaryText: summaryParts.join(" "),
    profileFacts,
    knowledgeFacts,
    unresolvedTopics,
    sourceTitles,
  };
}

function pushCandidate(
  target: LegacyEmploymentAdjustmentFactCandidate[],
  fieldKey: string,
  label: string,
  rawValue: string | null,
  dataType: "string" | "date" | "number" | "boolean",
  evidenceExcerpt: string,
  requiresHumanConfirmation = false,
) {
  const normalized =
    dataType === "date" ? normalizeLegacyDate(rawValue)
    : dataType === "boolean" ? normalizeLegacyBoolean(rawValue)
    : dataType === "number" ? normalizeLegacyNumberString(rawValue)
    : normalizeLegacyScalar(rawValue);

  if (!normalized) {
    return;
  }

  target.push({
    fieldKey,
    label,
    rawValue: normalized,
    dataType,
    confidence: requiresHumanConfirmation ? 0.92 : 0.99,
    evidenceExcerpt,
    requiresHumanConfirmation,
  });
}

export function buildLegacyEmploymentAdjustmentFactCandidates(
  caseData: LegacyEmploymentAdjustmentCaseData,
): LegacyEmploymentAdjustmentFactCandidate[] {
  const candidates: LegacyEmploymentAdjustmentFactCandidate[] = [];
  const source = `Legacy employment AOS case_data${caseData.case_id ? ` • ${caseData.case_id}` : ""}`;
  const travel = latestTravelEntry(caseData);
  const marriage = currentMarriage(caseData);
  const child = firstChildDependent(caseData);
  const parent1 = (caseData.parents ?? []).find((parent) => /father/i.test(normalizeWhitespace(parent.role)));
  const parent2 = (caseData.parents ?? []).find((parent) => /mother/i.test(normalizeWhitespace(parent.role)));
  const i20 = latestI20Entry(caseData);

  pushCandidate(candidates, "client_first_name", "Client first name", caseData.applicant?.name?.given ?? null, "string", source);
  pushCandidate(candidates, "client_middle_name", "Client middle name", caseData.applicant?.name?.middle ?? null, "string", source);
  pushCandidate(candidates, "client_last_name", "Client last name", caseData.applicant?.name?.family ?? null, "string", source);
  pushCandidate(candidates, "client_email", "Client email", caseData.applicant?.email ?? null, "string", source);
  pushCandidate(candidates, "client_phone", "Client phone", caseData.applicant?.phone ?? null, "string", source);
  pushCandidate(candidates, "client_date_of_birth", "Client date of birth", caseData.applicant?.dob ?? null, "date", source);
  pushCandidate(candidates, "client_country_of_citizenship", "Client country of citizenship", caseData.applicant?.country_of_citizenship ?? null, "string", source);
  pushCandidate(candidates, "client_birth_city", "Client city of birth", caseData.applicant?.city_of_birth ?? null, "string", source);
  pushCandidate(candidates, "client_birth_country", "Client country of birth", caseData.applicant?.country_of_birth ?? null, "string", source);
  pushCandidate(candidates, "client_gender", "Client gender", caseData.applicant?.sex ?? null, "string", source);
  pushCandidate(candidates, "client_marital_status", "Client marital status", normalizeMaritalStatus(caseData.applicant?.marital_status), "string", source);
  pushCandidate(candidates, "client_alien_number", "Client alien number", caseData.applicant?.a_number ?? null, "string", source);
  pushCandidate(candidates, "client_ssn", "Client SSN", caseData.applicant?.ssn ?? null, "string", source, true);
  pushCandidate(candidates, "passport_number", "Passport number", caseData.applicant?.passport?.number ?? null, "string", source);
  pushCandidate(candidates, "client_passport_issuing_country", "Passport issuing country", caseData.applicant?.passport?.country_of_issuance ?? null, "string", source);
  pushCandidate(candidates, "client_passport_expiration_date", "Passport expiration date", caseData.applicant?.passport?.expiration ?? null, "date", source);
  pushCandidate(candidates, "client_visa_number", "Visa number", caseData.applicant?.visa_at_last_entry?.number ?? null, "string", source);
  pushCandidate(candidates, "client_i94_number", "I-94 number", travel?.i94_number ?? caseData.i94?.number ?? null, "string", source);
  pushCandidate(candidates, "client_class_of_admission", "Class of admission", travel?.class_of_admission ?? caseData.i94?.class ?? null, "string", source);
  pushCandidate(candidates, "client_last_arrival_date", "Last arrival date", travel?.date_of_entry ?? caseData.i94?.date_of_entry ?? null, "date", source);
  pushCandidate(candidates, "client_authorized_stay_until", "Authorized stay until", travel?.admit_until ?? caseData.i94?.admit_until ?? null, "date", source);
  pushCandidate(candidates, "client_current_immigration_status", "Current immigration status", caseData.current_status?.class ?? null, "string", source);
  pushCandidate(candidates, "client_status_expires_on", "Current status expiration", caseData.current_status?.expires ?? null, "date", source);
  pushCandidate(candidates, "client_current_address_line1", "Current address line 1", buildAddressLine1(caseData.applicant?.mailing_address), "string", source);
  pushCandidate(candidates, "client_current_address_line2", "Current address line 2", buildAddressLine2(caseData.applicant?.mailing_address), "string", source);
  pushCandidate(candidates, "client_current_city", "Current city", caseData.applicant?.mailing_address?.city ?? null, "string", source);
  pushCandidate(candidates, "client_current_state", "Current state", caseData.applicant?.mailing_address?.state ?? null, "string", source);
  pushCandidate(candidates, "client_current_zip_code", "Current ZIP code", caseData.applicant?.mailing_address?.zip ?? null, "string", source);
  pushCandidate(candidates, "client_current_country", "Current country", caseData.applicant?.mailing_address?.country ?? null, "string", source);
  pushCandidate(candidates, "client_foreign_address_line1", "Most recent foreign address line 1", buildAddressLine1(caseData.applicant?.last_foreign_address), "string", source);
  pushCandidate(candidates, "client_foreign_city", "Most recent foreign city", caseData.applicant?.last_foreign_address?.city ?? null, "string", source);
  pushCandidate(candidates, "client_foreign_province", "Most recent foreign province", caseData.applicant?.last_foreign_address?.province ?? null, "string", source);
  pushCandidate(candidates, "client_foreign_postal_code", "Most recent foreign postal code", caseData.applicant?.last_foreign_address?.postal ?? null, "string", source);
  pushCandidate(candidates, "client_foreign_country", "Most recent foreign country", caseData.applicant?.last_foreign_address?.country ?? null, "string", source);

  pushCandidate(candidates, "employer_name", "Employer legal name", caseData.petitioner?.legal_name ?? null, "string", source);
  pushCandidate(candidates, "job_title", "Offered job title", caseData.i140?.job_title ?? null, "string", source);
  pushCandidate(candidates, "annual_salary", "Offered wage", caseData.i140?.offered_wage ?? null, "string", source);
  pushCandidate(candidates, "i140_receipt_number", "I-140 receipt number", caseData.i140?.receipt_number ?? null, "string", source, true);
  pushCandidate(candidates, "i140_priority_date", "I-140 priority date", caseData.i140?.priority_date ?? null, "date", source);
  pushCandidate(candidates, "i140_category", "I-140 category", normalizeEmploymentBasedCategory(caseData.i140?.category), "string", source);
  pushCandidate(candidates, "perm_case_number", "PERM case number", caseData.i140?.perm_case_number ?? null, "string", source);
  pushCandidate(candidates, "parent_1_full_name", "Parent 1 full name", buildNameValue({ given: parent1?.given, middle: parent1?.middle, family: parent1?.family }), "string", source);
  pushCandidate(candidates, "parent_1_date_of_birth", "Parent 1 date of birth", parent1?.dob ?? null, "date", source, true);
  pushCandidate(candidates, "parent_1_country_of_birth", "Parent 1 country of birth", parent1?.country_of_birth ?? null, "string", source);
  pushCandidate(candidates, "parent_2_full_name", "Parent 2 full name", buildNameValue({ given: parent2?.given, middle: parent2?.middle, family: parent2?.family }), "string", source);
  pushCandidate(candidates, "parent_2_date_of_birth", "Parent 2 date of birth", parent2?.dob ?? null, "date", source, true);
  pushCandidate(candidates, "parent_2_country_of_birth", "Parent 2 country of birth", parent2?.country_of_birth ?? null, "string", source);
  pushCandidate(candidates, "spouse_full_name", "Current spouse full name", buildNameValue(marriage?.spouse), "string", source);
  pushCandidate(candidates, "spouse_date_of_birth", "Current spouse date of birth", marriage?.spouse?.dob ?? null, "date", source, true);
  pushCandidate(candidates, "spouse_country_of_birth", "Current spouse country of birth", marriage?.spouse?.country_of_birth ?? null, "string", source);
  pushCandidate(candidates, "marriage_date", "Marriage date", marriage?.date_of_marriage ?? null, "date", source, true);
  pushCandidate(candidates, "marriage_country", "Marriage country", marriage?.place_of_marriage?.country ?? null, "string", source);
  pushCandidate(candidates, "number_of_children", "Number of children", String((caseData.dependents ?? []).filter((dependent) => /child|son|daughter/i.test(normalizeWhitespace(dependent.relationship))).length), "number", source);
  pushCandidate(candidates, "child_1_full_name", "First child full name", buildNameValue(child?.name), "string", source);
  pushCandidate(candidates, "child_1_date_of_birth", "First child date of birth", child?.dob ?? null, "date", source, true);
  pushCandidate(candidates, "child_1_country_of_birth", "First child country of birth", child?.country_of_birth ?? null, "string", source);
  pushCandidate(candidates, "height_feet", "Height feet", caseData.applicant?.height_ft ?? null, "number", source, true);
  pushCandidate(candidates, "height_inches", "Height inches", caseData.applicant?.height_in ?? null, "number", source, true);
  pushCandidate(candidates, "weight_pounds", "Weight pounds", caseData.applicant?.weight_lb ?? null, "number", source, true);
  pushCandidate(candidates, "eye_color", "Eye color", normalizeEyeOrHairColor(caseData.applicant?.eye_color), "string", source, true);
  pushCandidate(candidates, "hair_color", "Hair color", normalizeEyeOrHairColor(caseData.applicant?.hair_color), "string", source, true);
  pushCandidate(candidates, "client_has_been_arrested", "Ever arrested", String(caseData.eligibility_answers?.ever_arrested ?? ""), "boolean", source, true);
  pushCandidate(candidates, "client_ever_public_cash_assistance", "Ever received public cash assistance", String(caseData.eligibility_answers?.ever_public_cash_assistance ?? ""), "boolean", source, true);
  pushCandidate(candidates, "household_size", "Household size", String(caseData.eligibility_answers?.household_size ?? ""), "number", source, true);
  pushCandidate(candidates, "household_assets_value", "Household assets value", caseData.eligibility_answers?.household_assets_value ?? null, "string", source, true);
  pushCandidate(candidates, "current_school_name", "Current school name", i20?.school ?? null, "string", source);
  pushCandidate(candidates, "current_school_program", "Current school program", i20?.program ?? null, "string", source);
  pushCandidate(candidates, "current_school_start_date", "Current school program start", i20?.program_start ?? null, "date", source, true);
  pushCandidate(candidates, "current_school_end_date", "Current school program end", i20?.program_end ?? null, "date", source, true);

  return candidates;
}

