import { z } from "zod";
import { emptyApplication } from "./application-schema";
import {
  DECLARATION_VERSION,
  declarationFailures,
  declarationKeys,
  declarationSchema,
  dueDiligenceKeys,
  emptyDeclaration,
  requiredDeclarations,
  type Declaration,
} from "./application-declaration";
import { singaporeDate } from "./application-particulars";
import type { ApplicationRecord } from "./application-record";
import {
  staffDetailFailures,
  staffDetailKeys,
  staffDetailSections,
  staffDetailValues,
  type StaffDetailSection,
} from "./staff-details";
const values = z.record(z.string(), z.string().max(400));
export const staffCreateSchema = z
  .object({
    requestId: z.uuid().toLowerCase(),
    applicant: values,
    particulars: values,
    loanContext: values,
    assessment: values,
    declaration: z
      .object({
        answers: values,
        signed: z.boolean(),
        signedOn: z.string().max(10),
      })
      .strict(),
  })
  .strict();
export type StaffCreateInput = z.infer<typeof staffCreateSchema>;
export type StaffDeclarationDraft = StaffCreateInput["declaration"];
const detailKeys = ["bankruptcyDetails", "convictionDetails"] as const;
export const emptyStaffDeclaration = (): StaffDeclarationDraft => ({
  answers: Object.fromEntries(
    [...dueDiligenceKeys, ...detailKeys].map((key) => [key, ""]),
  ),
  signed: false,
  signedOn: "",
});
const emptyRecord = { fields: emptyApplication } as Pick<
  ApplicationRecord,
  "fields" | "particulars" | "loanContext" | "assessment"
>;
export const emptyStaffSection = (section: StaffDetailSection) =>
  staffDetailValues(emptyRecord, section);

function asDeclaration(answers: Record<string, string>): Declaration {
  const base = {
    ...emptyDeclaration,
    ...Object.fromEntries(
      [...dueDiligenceKeys, ...detailKeys].map((key) => [
        key,
        answers[key] ?? "",
      ]),
    ),
  } as Declaration;
  const required = requiredDeclarations(base);
  return {
    ...base,
    ...Object.fromEntries(
      declarationKeys.map((key) => [key, required.includes(key)]),
    ),
    version: DECLARATION_VERSION,
  };
}
export function staffDeclarationFailures(
  draft: StaffDeclarationDraft,
  today = singaporeDate(),
): Record<string, string> {
  const failures: Record<string, string> = {},
    answerKeys: readonly string[] = [...dueDiligenceKeys, ...detailKeys];
  for (const [key, message] of Object.entries(
    declarationFailures(asDeclaration(draft.answers)),
  ))
    if (answerKeys.includes(key)) failures[key] = message;
  if (!draft.signed)
    failures.signed = "Confirm the applicant signed the declaration form.";
  if (!z.iso.date().safeParse(draft.signedOn).success)
    failures.signedOn = "Enter the date the applicant signed.";
  else if (draft.signedOn > today)
    failures.signedOn = "Enter a date that is not in the future.";
  else if (draft.signedOn < "2020-01-01")
    failures.signedOn = "Enter a valid date.";
  return failures;
}
export function staffCreateFailures(
  input: Omit<StaffCreateInput, "requestId">,
  today?: string,
): Record<string, string> {
  const failures: Record<string, string> = {};
  for (const section of staffDetailSections) {
    const sectionFailures = staffDetailFailures(section, input[section]);
    for (const key of staffDetailKeys(section, input[section]))
      if (sectionFailures[key])
        failures[`${section}.${key}`] = sectionFailures[key];
  }
  for (const [key, message] of Object.entries(
    staffDeclarationFailures(input.declaration, today),
  ))
    failures[`declaration.${key}`] = message;
  return failures;
}
export function staffDeclarationRecord(
  draft: StaffDeclarationDraft,
  recordedBy: string,
) {
  const parsed = declarationSchema.safeParse(asDeclaration(draft.answers));
  return parsed.success
    ? { ...parsed.data, capture: "paper", signedOn: draft.signedOn, recordedBy }
    : null;
}
