import { z } from "zod";
import { ETHIOPIAN_REGIONS } from "@edr/types";

import { isValidPhone } from "@/components/PhoneField";

export type CompanyStep =
  | "company"
  | "personnel"
  | "contact"
  | "poa"
  | "documents"
  | "additional";

export const onboardingSchema = z.object({
  companyName: z.string().min(1, "Company name is required"),
  companyEmail: z.string().email("Invalid email address"),
  companyPhone: z
    .string()
    .min(1, "Company phone is required")
    .refine(isValidPhone, "Enter a valid phone number"),
  companyLocation: z.string().min(1, "Location is required"),
  // Derived from the eTrade address parts (kebele/woreda/zone/region); no
  // standalone input — the granular fields live in the registration section.
  companyAddress: z.string().optional(),
  tinNumber: z.string().regex(/^\d{10}$/, "TIN must be exactly 10 digits"),
  vatNumber: z
    .string()
    .min(1, "VAT number is required")
    .length(10, "VAT number must be exactly 10 digits"),
  fanNumber: z.string().length(16, "FAN must be exactly 16 digits"),
  licenceNumber: z.string().optional(),
  statusDescription: z.string().optional(),
  dateRegistered: z.string().optional(),
  renewedFrom: z.string().optional(),
  renewalDate: z.string().optional(),
  renewedTo: z.string().optional(),
  // Address fields are user-entered and required (the registration/license
  // fields above are read-only confirmations pulled from eTrade).
  // Region is a closed set; zone/woreda/kebele stay free text until the platform
  // has an authoritative dataset of Ethiopian zones/woredas/kebeles.
  //
  // Deliberately `.refine` over `z.enum`: the form needs "" as its unselected
  // sentinel (default value, and legacy rows whose region isn't in the list). A
  // literal union makes "" untypable, which also splits the resolver's
  // input/output types and breaks useForm's inference for every other field.
  region: z
    .string()
    .refine((v) => (ETHIOPIAN_REGIONS as readonly string[]).includes(v), {
      message: "Region is required",
    }),
  zone: z.string().min(1, "Zone is required"),
  woreda: z.string().min(1, "Woreda is required"),
  kebele: z.string().min(1, "Kebele is required"),
  houseNo: z.string().min(1, "House number is required"),
  contactPersonName: z.string().min(1, "Contact person name is required"),
  contactPersonPosition: z.string().optional(),
  contactPersonEmail: z
    .string()
    .email("Invalid email address")
    .optional()
    .or(z.literal("")),
  contactPersonPhone: z
    .string()
    .min(1, "Contact person phone is required")
    .refine(isValidPhone, "Enter a valid phone number"),
  generalManagerName: z.string().min(1, "Manager name is required"),
  generalManagerEmail: z.string().email("Invalid Manager email"),
  generalManagerPhone: z
    .string()
    .min(1, "Manager phone is required")
    .refine(isValidPhone, "Enter a valid phone number"),
  poaName: z.string().optional(),
  poaPhone: z
    .string()
    .optional()
    .refine((v) => !v || isValidPhone(v), "Enter a valid phone number"),
  poaAddress: z.string().optional(),
  poaEmail: z
    .string()
    .optional()
    .refine(
      (v) => !v || z.string().email().safeParse(v).success,
      "Invalid email address",
    ),
  poaLocation: z.string().optional(),
});

export type FormData = z.infer<typeof onboardingSchema>;

/** fileKey of the delegation letter uploaded on the Power of Attorney step. */
export const POA_DELEGATION_FILE_KEY = "poa_delegation_letter";

export const POA_FIELDS = [
  "poaName",
  "poaPhone",
  "poaEmail",
  "poaLocation",
  "poaAddress",
] as const satisfies readonly (keyof FormData)[];

/** True once the customer has entered any Power of Attorney detail. */
export const hasPoaDetails = (d: Partial<FormData>) =>
  POA_FIELDS.some((f) => d[f]?.trim());

/**
 * A freight forwarder acts on other companies' behalf, so its PoA is mandatory
 * rather than optional. Everyone else keeps the optional PoA — but once they
 * start filling it in, the identifying fields have to be complete (the
 * delegation-letter upload is enforced alongside this, in CompanyProfileForm,
 * since files live outside the form state).
 */
export function buildOnboardingSchema(requirePoa: boolean) {
  if (!requirePoa) return onboardingSchema;
  return onboardingSchema.superRefine((d, ctx) => {
    const required: [keyof FormData, string][] = [
      ["poaName", "PoA name is required for freight forwarders"],
      ["poaEmail", "PoA email is required for freight forwarders"],
      ["poaPhone", "PoA phone is required for freight forwarders"],
    ];
    for (const [path, message] of required) {
      if (!d[path]?.trim()) {
        ctx.addIssue({ code: z.ZodIssueCode.custom, path: [path], message });
      }
    }
  });
}

export const stepFields: Record<CompanyStep, (keyof FormData)[]> = {
  company: [
    "companyName",
    "companyEmail",
    "companyPhone",
    "companyLocation",
    "companyAddress",
    "tinNumber",
    "vatNumber",
    "fanNumber",
    "licenceNumber",
    "statusDescription",
    "dateRegistered",
    "renewedFrom",
    "renewalDate",
    "renewedTo",
    "region",
    "zone",
    "woreda",
    "kebele",
    "houseNo",
  ],
  personnel: [
    "generalManagerName",
    "generalManagerEmail",
    "generalManagerPhone",
  ],
  contact: [
    "contactPersonName",
    "contactPersonPosition",
    "contactPersonEmail",
    "contactPersonPhone",
  ],
  poa: [...POA_FIELDS],
  documents: [],
  additional: [],
};
