import { z } from "zod";
import {
  applicationFieldSchema,
  employmentOptions,
} from "./application-schema";
import { interests } from "./contact-schema";
import {
  emptyParticulars,
  myinfoLockedParticulars,
  optionalParticulars,
  particularOptions,
  particularsFailures,
  particularsKeys,
  particularsLabels,
  particularsSchema,
  type Particulars,
} from "./application-particulars";
import {
  emptyLoanContext,
  loanContextFailures,
  loanContextKeys,
  loanContextLabels,
  loanContextOptional,
  loanContextOptions,
  loanContextSchema,
  visibleLoanContextKeys,
  type LoanContext,
  type LoanContextKey,
} from "./application-loan-context";
import {
  assessmentLabels,
  assessmentSchema,
  emptyAssessment,
  myinfoLockedAssessment,
  type Assessment,
} from "./application-assessment";
import type { ApplicationRecord } from "./application-record";
export const staffDetailSections = [
  "applicant",
  "particulars",
  "loanContext",
  "assessment",
] as const;
export type StaffDetailSection = (typeof staffDetailSections)[number];
export const staffDetailsSchema = z
  .object({
    revision: z.number().int().nonnegative(),
    section: z.enum(staffDetailSections),
    values: z.record(z.string(), z.string().max(300)),
  })
  .strict();
type Values = Record<string, string>;
const applicantKeys = [
  "name",
  "email",
  "phone",
  "interest",
  "amount",
  "employment",
  "monthlyIncome",
] as const;
const labels: Record<StaffDetailSection, Record<string, string>> = {
  applicant: {
    name: "Full name",
    email: "Email",
    phone: "Phone",
    interest: "Loan type",
    amount: "Requested amount (SGD)",
    employment: "Employment",
    monthlyIncome: "Monthly income (SGD)",
  },
  particulars: particularsLabels,
  loanContext: loanContextLabels,
  assessment: assessmentLabels,
};
const options: Record<
  StaffDetailSection,
  Partial<Record<string, readonly string[]>>
> = {
  applicant: { interest: interests, employment: employmentOptions },
  particulars: particularOptions,
  loanContext: loanContextOptions,
  assessment: {},
};
const schemas = {
  applicant: applicationFieldSchema,
  particulars: particularsSchema,
  loanContext: loanContextSchema,
  assessment: assessmentSchema,
} as Record<StaffDetailSection, z.ZodType<Values>>;
export const staffDetailTitles: Record<StaffDetailSection, string> = {
  applicant: "Applicant details",
  particulars: "Particulars and address",
  loanContext: "About this loan",
  assessment: "Declared employment and expenses",
};
export const staffDetailEditLabels: Record<StaffDetailSection, string> = {
  applicant: "Edit applicant details",
  particulars: "Edit particulars and address",
  loanContext: "Edit loan details",
  assessment: "Edit employment and expenses",
};

export function staffDetailValues(
  record: Pick<
    ApplicationRecord,
    "fields" | "particulars" | "loanContext" | "assessment"
  >,
  section: StaffDetailSection,
): Values {
  if (section === "applicant") return { ...record.fields };
  const [keys, empty, stored] =
    section === "particulars"
      ? [particularsKeys, emptyParticulars, record.particulars]
      : section === "loanContext"
        ? [loanContextKeys, emptyLoanContext, record.loanContext]
        : [Object.keys(emptyAssessment), emptyAssessment, record.assessment];
  return Object.fromEntries(
    keys.map((key) => [
      key,
      (stored as Values | undefined)?.[key] ?? (empty as Values)[key],
    ]),
  );
}
export function staffDetailKeys(
  section: StaffDetailSection,
  values: Values,
): readonly string[] {
  if (section === "applicant") return applicantKeys;
  if (section === "particulars") return particularsKeys;
  if (section === "loanContext")
    return visibleLoanContextKeys(values as LoanContext);
  return Object.keys(emptyAssessment);
}
export const staffDetailLabel = (section: StaffDetailSection, key: string) =>
  labels[section][key] ?? key;
export const staffDetailOptions = (section: StaffDetailSection, key: string) =>
  options[section][key];
export const staffDetailOptional = (
  section: StaffDetailSection,
  key: string,
  values: Values,
) =>
  section === "particulars"
    ? optionalParticulars.includes(key as (typeof particularsKeys)[number])
    : section === "loanContext"
      ? loanContextOptional(key as LoanContextKey, values as LoanContext)
      : false;
export const staffDetailInputType = (key: string) =>
  key === "dob" || key === "dateJoined"
    ? "date"
    : key === "email"
      ? "email"
      : key === "phone"
        ? "tel"
        : "text";
export function lockedStaffDetails(
  record: Pick<ApplicationRecord, "myinfo">,
  section: StaffDetailSection,
  stored: Values,
): string[] {
  const myinfo = record.myinfo;
  if (!myinfo) return [];
  if (section === "applicant")
    return myinfo.principalName &&
      myinfo.principalName.trim().toLowerCase() ===
        stored.name.trim().toLowerCase()
      ? ["name"]
      : [];
  if (section === "particulars")
    return myinfoLockedParticulars(stored as Particulars, myinfo.identity);
  if (section === "assessment")
    return myinfoLockedAssessment(stored as Assessment, myinfo);
  return [];
}
export function staffDetailFailures(
  section: StaffDetailSection,
  values: Values,
): Record<string, string> {
  if (section === "particulars")
    return particularsFailures(values as Particulars) as Record<string, string>;
  if (section === "loanContext")
    return loanContextFailures(values as LoanContext) as Record<string, string>;
  const parsed = schemas[section].safeParse(values),
    failures: Record<string, string> = {};
  if (!parsed.success)
    for (const issue of parsed.error.issues) {
      const key = issue.path[0];
      if (typeof key === "string") failures[key] ??= issue.message;
    }
  return failures;
}
export function parseStaffDetails(
  section: StaffDetailSection,
  values: Values,
): Values | null {
  const parsed = schemas[section].safeParse(values);
  return parsed.success ? parsed.data : null;
}
export function staffDetailAudit(
  value: string,
): { label: string; value: string } | null {
  try {
    const [entry] = Object.entries(
      z.record(z.string(), z.string()).parse(JSON.parse(value)),
    );
    const [section, key] = entry[0].split(".");
    return (staffDetailSections as readonly string[]).includes(section) && key
      ? {
          label: staffDetailLabel(section as StaffDetailSection, key),
          value: entry[1],
        }
      : null;
  } catch {
    return null;
  }
}
