/**
 * Définitions des champs dynamiques utilisés dans les form templates.
 * Stockés en jsonb (`form_template.fields`), édités par l'admin,
 * rendus par <DynamicForm /> côté public.
 */

import { z } from "zod";

export type FieldType =
  | "text"
  | "email"
  | "phone"
  | "number"
  | "date"
  | "textarea"
  | "select"
  | "radio"
  | "checkbox"
  | "file";

/**
 * Catégories de fichiers proposées dans le form builder.
 * Mappées vers une chaîne `accept` HTML standard.
 */
export type FileAcceptCategory = "image" | "pdf" | "word" | "excel" | "any";

export const FILE_ACCEPT_PATTERNS: Record<FileAcceptCategory, string> = {
  image: "image/*",
  pdf: ".pdf,application/pdf",
  word: ".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  excel: ".xls,.xlsx,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  any: "",
};

export const FILE_ACCEPT_LABELS: Record<FileAcceptCategory, string> = {
  image: "Images",
  pdf: "PDF",
  word: "Word",
  excel: "Excel",
  any: "Tout fichier",
};

/** Construit la chaîne `accept` à passer à l'input HTML depuis les catégories. */
export function buildAcceptString(categories?: FileAcceptCategory[]): string {
  if (!categories || categories.length === 0) return "";
  if (categories.includes("any")) return "";
  return categories.map((c) => FILE_ACCEPT_PATTERNS[c]).filter(Boolean).join(",");
}

export interface FieldOption {
  /** Valeur stockée (ex: "sas"). */
  value: string;
  /** Label affiché (ex: "SAS / SASU"). */
  label: string;
}

export interface FormField {
  /** ID stable, utilisé comme clé du formData. Doit être unique dans le form. */
  id: string;
  type: FieldType;
  label: string;
  /** Texte d'aide sous le label. */
  description?: string;
  /** Placeholder dans l'input. */
  placeholder?: string;
  required?: boolean;
  /** Pour select / radio. */
  options?: FieldOption[];
  /** Pour text / textarea : longueur min/max. */
  minLength?: number;
  maxLength?: number;
  /** Pour number : bornes. */
  min?: number;
  max?: number;
  /** Pour file : catégories de fichiers acceptées (par défaut PDF + Word + image). */
  acceptCategories?: FileAcceptCategory[];
  /** Pour file : autoriser plusieurs fichiers (défaut false). */
  multiple?: boolean;
  /** Pour file : taille max d'un fichier en Mo (défaut 25). */
  maxSizeMb?: number;
}

export interface DocumentRequest {
  id: string;
  label: string;
  description?: string;
  required?: boolean;
  /** Catégories de fichiers acceptées (par défaut PDF + image). */
  acceptCategories?: FileAcceptCategory[];
  /** Autoriser plusieurs fichiers (défaut false). */
  multiple?: boolean;
  /** Taille max d'un fichier en Mo (défaut 25). */
  maxSizeMb?: number;
  /** Document d'exemple fourni par l'admin que le client peut télécharger. */
  sampleFile?: {
    name: string;
    /** Chemin relatif depuis UPLOADS_DIR (ex: _samples/creation-de-societe/d_abc/uuid-modele.pdf). */
    path: string;
    sizeBytes?: number;
    mimeType?: string;
  };
}

/* ─── Validation Zod runtime ────────────────────────────────────────── */

export const fieldSchema: z.ZodType<FormField> = z.object({
  id: z.string().min(1),
  type: z.enum([
    "text",
    "email",
    "phone",
    "number",
    "date",
    "textarea",
    "select",
    "radio",
    "checkbox",
    "file",
  ]),
  label: z.string().min(1),
  description: z.string().optional(),
  placeholder: z.string().optional(),
  required: z.boolean().optional(),
  options: z
    .array(
      z.object({
        value: z.string().min(1),
        label: z.string().min(1),
      })
    )
    .optional(),
  minLength: z.number().int().nonnegative().optional(),
  maxLength: z.number().int().positive().optional(),
  min: z.number().optional(),
  max: z.number().optional(),
  acceptCategories: z
    .array(z.enum(["image", "pdf", "word", "excel", "any"]))
    .optional(),
  multiple: z.boolean().optional(),
  maxSizeMb: z.number().positive().optional(),
});

export const documentRequestSchema: z.ZodType<DocumentRequest> = z.object({
  id: z.string().min(1),
  label: z.string().min(1),
  description: z.string().optional(),
  required: z.boolean().optional(),
  acceptCategories: z
    .array(z.enum(["image", "pdf", "word", "excel", "any"]))
    .optional(),
  multiple: z.boolean().optional(),
  maxSizeMb: z.number().positive().optional(),
  sampleFile: z
    .object({
      name: z.string(),
      path: z.string(),
      sizeBytes: z.number().optional(),
      mimeType: z.string().optional(),
    })
    .optional(),
});

/**
 * Construit un schema Zod dynamique pour valider la soumission utilisateur
 * en fonction de la définition des champs du template.
 */
export function buildSubmissionSchema(fields: FormField[]) {
  const shape: Record<string, z.ZodTypeAny> = {};

  for (const f of fields) {
    // Les champs de type fichier sont validés à part côté server
    // (ils transitent en multipart, pas dans le payload JSON-validé).
    if (f.type === "file") continue;

    let s: z.ZodTypeAny;
    switch (f.type) {
      case "email":
        s = z.string().email("Email invalide");
        break;
      case "phone":
        s = z
          .string()
          .regex(/^[\d\s+()-]+$/, "Numéro de téléphone invalide");
        break;
      case "number": {
        let n = z.coerce.number({ message: "Nombre attendu" });
        if (typeof f.min === "number") n = n.min(f.min);
        if (typeof f.max === "number") n = n.max(f.max);
        s = n;
        break;
      }
      case "date":
        s = z.coerce.date();
        break;
      case "checkbox":
        s = z.coerce.boolean();
        break;
      case "select":
      case "radio":
        if (f.options && f.options.length > 0) {
          s = z.enum(
            f.options.map((o) => o.value) as [string, ...string[]]
          );
        } else {
          s = z.string();
        }
        break;
      default:
        // text, textarea
        s = z.string();
        if (f.minLength) s = (s as z.ZodString).min(f.minLength);
        if (f.maxLength) s = (s as z.ZodString).max(f.maxLength);
    }

    if (!f.required) {
      s = s.optional();
    } else if (f.type === "checkbox") {
      // Required + checkbox = doit être true
      s = z.literal(true, { message: "Ce champ est requis" });
    }

    shape[f.id] = s;
  }

  return z.object(shape);
}

/* ─── Helpers ───────────────────────────────────────────────────────── */

/** Génère un id unique pour un nouveau champ ou un nouveau document. */
export function newId(prefix: string): string {
  return `${prefix}_${Math.random().toString(36).slice(2, 8)}`;
}

export const FIELD_TYPE_LABELS: Record<FieldType, string> = {
  text: "Texte court",
  email: "Email",
  phone: "Téléphone",
  number: "Nombre",
  date: "Date",
  textarea: "Texte long",
  select: "Liste déroulante",
  radio: "Choix unique",
  checkbox: "Case à cocher",
  file: "Fichier",
};
