"use client";

import { ChangeEvent, useMemo, useState } from "react";
import { CheckCircle2, FileText, FileUp, Loader2, ShieldAlert, ShieldCheck, Upload } from "lucide-react";
import { cn } from "@/lib/utils";

type KycStatus = "NOT_STARTED" | "PENDING" | "APPROVED" | "REJECTED" | "EXPIRED";
type KycDocumentType = "IDENTITY_FRONT" | "IDENTITY_BACK" | "PROOF_OF_ADDRESS" | "SUPPORTING_DOCUMENT";

type KycDocument = {
  id: string;
  type: KycDocumentType | string;
  status: string;
  uploadedAt: string;
};

type KycDecision = {
  id: string;
  status: KycStatus;
  reason: string;
  createdAt: string;
};

type KycCase = {
  id: string;
  status: KycStatus;
  openedAt: string;
  decidedAt: string | null;
  expiresAt: string | null;
  documents: KycDocument[];
  decisions: KycDecision[];
};

type ApiPayload = {
  ok: boolean;
  data?: {
    case: {
      id: string;
      status: KycStatus;
    };
    documents: KycDocument[];
  };
  error?: {
    message?: string;
  };
};

const requiredDocuments: Array<{
  type: Exclude<KycDocumentType, "SUPPORTING_DOCUMENT">;
  title: string;
  body: string;
}> = [
  {
    type: "IDENTITY_FRONT",
    title: "Pièce d'identité recto",
    body: "Carte d'identité, passeport ou permis, lisible."
  },
  {
    type: "IDENTITY_BACK",
    title: "Pièce d'identité verso",
    body: "Obligatoire si votre document possède un verso."
  },
  {
    type: "PROOF_OF_ADDRESS",
    title: "Justificatif de domicile",
    body: "Facture ou document officiel récent à votre nom."
  }
];

const accept = "image/jpeg,image/png,image/webp,application/pdf";

export function KycVerificationPanel({ initialCases }: { initialCases: KycCase[] }) {
  const [cases, setCases] = useState(initialCases);
  const [requiredFiles, setRequiredFiles] = useState<Partial<Record<KycDocumentType, File>>>({});
  const [supportFiles, setSupportFiles] = useState<File[]>([]);
  const [loadingKey, setLoadingKey] = useState<string | null>(null);
  const [message, setMessage] = useState("");

  const pendingCase = useMemo(() => cases.find((kycCase) => kycCase.status === "PENDING") ?? null, [cases]);
  const approvedCase = useMemo(() => cases.find((kycCase) => kycCase.status === "APPROVED") ?? null, [cases]);
  const latestCase = cases[0] ?? null;
  const visibleDocuments = useMemo(() => cases.flatMap((kycCase) => kycCase.documents).slice(0, 6), [cases]);
  const supportNote = "Formats acceptés : JPG, PNG, WEBP ou PDF. 8 Mo maximum par fichier, 5 fichiers par envoi.";

  function hasDocument(type: KycDocumentType) {
    return Boolean(pendingCase?.documents.some((document) => document.type === type && document.status !== "rejected"));
  }

  function latestDocumentStatus(type: KycDocumentType) {
    return pendingCase?.documents.find((document) => document.type === type)?.status ?? null;
  }

  function onRequiredFileChange(type: KycDocumentType, event: ChangeEvent<HTMLInputElement>) {
    const file = event.currentTarget.files?.[0];
    setRequiredFiles((current) => ({ ...current, [type]: file }));
  }

  function onSupportFilesChange(event: ChangeEvent<HTMLInputElement>) {
    setSupportFiles(Array.from(event.currentTarget.files ?? []));
  }

  async function uploadRequired(type: Exclude<KycDocumentType, "SUPPORTING_DOCUMENT">) {
    const file = requiredFiles[type];
    if (!file) {
      setMessage("Ajoutez un fichier avant l'envoi.");
      return;
    }
    await uploadDocuments(type, [file]);
    setRequiredFiles((current) => ({ ...current, [type]: undefined }));
  }

  async function uploadSupportDocuments() {
    if (!supportFiles.length) {
      setMessage("Ajoutez au moins un fichier à transmettre au support.");
      return;
    }
    await uploadDocuments("SUPPORTING_DOCUMENT", supportFiles);
    setSupportFiles([]);
  }

  async function uploadDocuments(documentType: KycDocumentType, files: File[]) {
    setLoadingKey(documentType);
    setMessage("");
    const form = new FormData();
    form.append("documentType", documentType);
    files.forEach((file) => form.append("files", file));

    try {
      const response = await fetch("/api/kyc/documents", { method: "POST", body: form });
      const payload = (await response.json()) as ApiPayload;
      if (!payload.ok || !payload.data) {
        setMessage(payload.error?.message ?? "Envoi impossible pour le moment.");
        return;
      }

      mergeUploadedDocuments(payload.data.case, payload.data.documents);
      setMessage("Document transmis au support.");
    } catch {
      setMessage("Connexion interrompue pendant l'envoi.");
    } finally {
      setLoadingKey(null);
    }
  }

  function mergeUploadedDocuments(uploadedCase: { id: string; status: KycStatus }, documents: KycDocument[]) {
    setCases((currentCases) => {
      const index = currentCases.findIndex((kycCase) => kycCase.id === uploadedCase.id);
      if (index === -1) {
        return [
          {
            id: uploadedCase.id,
            status: uploadedCase.status,
            openedAt: new Date().toISOString(),
            decidedAt: null,
            expiresAt: null,
            documents,
            decisions: []
          },
          ...currentCases
        ];
      }

      return currentCases.map((kycCase, currentIndex) => {
        if (currentIndex !== index) return kycCase;
        const existingIds = new Set(kycCase.documents.map((document) => document.id));
        return {
          ...kycCase,
          status: uploadedCase.status,
          documents: [...documents.filter((document) => !existingIds.has(document.id)), ...kycCase.documents]
        };
      });
    });
  }

  return (
    <div className="mx-auto w-full max-w-[700px] space-y-2.5">
      <section className="rounded-lg border border-white/10 bg-[#101521] p-3 shadow-panel">
        <div className="flex items-start gap-2.5">
          <span
            className={cn(
              "grid h-9 w-9 shrink-0 place-items-center rounded-lg",
              pendingCase ? "bg-gold/10 text-gold" : approvedCase ? "bg-felt/15 text-felt" : "bg-felt/10 text-felt"
            )}
          >
            {pendingCase ? <ShieldAlert className="h-4 w-4" /> : <ShieldCheck className="h-4 w-4" />}
          </span>
          <div className="min-w-0 flex-1">
            <p className="text-[11px] font-bold uppercase tracking-[0.14em] text-felt">Vérification</p>
            <h1 className="mt-1 text-lg font-bold text-white">
              {pendingCase ? "Vérification requise" : approvedCase ? "Compte validé" : "Aucune vérification requise"}
            </h1>
            <p className="mt-1.5 text-xs leading-5 text-slate-400">
              {pendingCase
                ? "Le support vous demande d'envoyer une pièce d'identité recto/verso et un justificatif de domicile."
                : approvedCase
                  ? "Vérification terminée par le support, votre compte est validé."
                : "Votre compte ne nécessite pas de vérification pour le moment. Si le support vous demande un document, utilisez le formulaire complémentaire ci-dessous."}
            </p>
            {pendingCase?.decisions[0]?.reason ? (
              <div className="mt-2 rounded-lg border border-gold/20 bg-gold/10 px-2.5 py-2 text-xs font-semibold text-gold">
                {pendingCase.decisions[0].reason}
              </div>
            ) : null}
          </div>
        </div>
      </section>

      {pendingCase ? (
        <section className="rounded-lg border border-white/10 bg-[#101521] p-3 shadow-panel">
          <div className="flex items-center justify-between gap-3">
            <div>
              <h2 className="text-sm font-bold text-white">Documents demandés</h2>
              <p className="mt-0.5 text-[11px] font-semibold text-slate-500">Stockage privé, accès réservé au support habilité.</p>
            </div>
            <span className="rounded-full border border-white/10 bg-white/[0.04] px-2 py-1 text-[11px] font-bold text-slate-300">
              {requiredDocuments.filter((document) => hasDocument(document.type)).length}/3 reçus
            </span>
          </div>

          <div className="mt-2.5 space-y-2">
            {requiredDocuments.map((document) => {
              const received = hasDocument(document.type);
              const documentStatus = latestDocumentStatus(document.type);
              const selectedFile = requiredFiles[document.type];
              const loading = loadingKey === document.type;
              return (
                <article key={document.type} className="rounded-lg border border-white/10 bg-white/[0.035] p-2.5">
                  <div className="flex items-start gap-2.5">
                    <span className={cn("grid h-8 w-8 shrink-0 place-items-center rounded-lg", received ? "bg-felt/10 text-felt" : "bg-white/[0.06] text-slate-300")}>
                      {received ? <CheckCircle2 className="h-4 w-4" /> : <FileText className="h-4 w-4" />}
                    </span>
                    <div className="min-w-0 flex-1">
                      <div className="flex items-center justify-between gap-2">
                        <h3 className="text-xs font-bold text-white">{document.title}</h3>
                        <span className={cn("rounded-full px-2 py-0.5 text-[10px] font-bold uppercase", documentStatus === "rejected" ? "bg-ember/10 text-ember" : received ? "bg-felt/10 text-felt" : "bg-gold/10 text-gold")}>
                          {documentStatus === "accepted" ? "Validé" : documentStatus === "rejected" ? "À renvoyer" : received ? "Reçu" : "À envoyer"}
                        </span>
                      </div>
                      <p className="mt-0.5 text-[11px] leading-4 text-slate-500">{document.body}</p>
                      <div className="mt-2 grid gap-2 sm:grid-cols-[1fr_auto]">
                        <label className="flex min-h-9 cursor-pointer items-center gap-2 rounded-lg border border-white/10 bg-ink-900 px-2.5 text-xs font-semibold text-slate-300">
                          <FileUp className="h-4 w-4 shrink-0 text-felt" />
                          <span className="truncate">{selectedFile?.name ?? "Choisir un fichier"}</span>
                          <input type="file" accept={accept} className="sr-only" onChange={(event) => onRequiredFileChange(document.type, event)} />
                        </label>
                        <button
                          onClick={() => void uploadRequired(document.type)}
                          disabled={loading || !selectedFile}
                          className="flex h-9 items-center justify-center gap-2 rounded-lg bg-felt px-3 text-xs font-bold text-ink-950 disabled:cursor-not-allowed disabled:opacity-50"
                        >
                          {loading ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Upload className="h-3.5 w-3.5" />}
                          Envoyer
                        </button>
                      </div>
                    </div>
                  </div>
                </article>
              );
            })}
          </div>
        </section>
      ) : null}

      <section className="rounded-lg border border-white/10 bg-[#101521] p-3 shadow-panel">
        <div className="flex items-start gap-2.5">
          <span className="grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-white/[0.06] text-felt">
            <FileUp className="h-4 w-4" />
          </span>
          <div className="min-w-0 flex-1">
            <h2 className="text-sm font-bold text-white">Document complémentaire</h2>
            <p className="mt-1 text-xs leading-5 text-slate-400">
              Envoyez ici les images ou PDF demandés par le support, même si aucune vérification n'est ouverte.
            </p>
            <div className="mt-2 grid gap-2 sm:grid-cols-[1fr_auto]">
              <label className="flex min-h-9 cursor-pointer items-center gap-2 rounded-lg border border-white/10 bg-ink-900 px-2.5 text-xs font-semibold text-slate-300">
                <FileText className="h-4 w-4 shrink-0 text-felt" />
                <span className="truncate">
                  {supportFiles.length ? `${supportFiles.length} fichier(s) sélectionné(s)` : "Ajouter images ou PDF"}
                </span>
                <input type="file" multiple accept={accept} className="sr-only" onChange={onSupportFilesChange} />
              </label>
              <button
                onClick={() => void uploadSupportDocuments()}
                disabled={loadingKey === "SUPPORTING_DOCUMENT" || !supportFiles.length}
                className="flex h-9 items-center justify-center gap-2 rounded-lg border border-felt/30 bg-felt/10 px-3 text-xs font-bold text-felt disabled:cursor-not-allowed disabled:opacity-50"
              >
                {loadingKey === "SUPPORTING_DOCUMENT" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Upload className="h-3.5 w-3.5" />}
                Envoyer au support
              </button>
            </div>
            <p className="mt-2 text-[11px] leading-4 text-slate-500">{supportNote}</p>
          </div>
        </div>
      </section>

      {message ? (
        <div className="rounded-lg border border-white/10 bg-white/[0.04] px-3 py-2 text-xs font-semibold text-slate-300">{message}</div>
      ) : null}

      <section className="rounded-lg border border-white/10 bg-[#101521] p-3 shadow-panel">
        <div className="flex items-center justify-between gap-3">
          <h2 className="text-sm font-bold text-white">Historique</h2>
          <span className="text-[11px] font-bold text-slate-500">{latestCase ? statusLabel(latestCase.status) : "Aucun dossier"}</span>
        </div>
        <div className="mt-2 divide-y divide-white/10">
          {visibleDocuments.map((document) => (
            <div key={document.id} className="flex items-center justify-between gap-3 py-2 text-xs">
              <span className="truncate font-semibold text-slate-300">{documentLabel(document.type)}</span>
              <span className="shrink-0 text-[11px] font-bold text-slate-500">{formatDate(document.uploadedAt)}</span>
            </div>
          ))}
          {!visibleDocuments.length ? (
            <div className="py-2 text-xs font-semibold text-slate-500">Aucun document transmis.</div>
          ) : null}
        </div>
      </section>
    </div>
  );
}

function documentLabel(type: string) {
  if (type === "IDENTITY_FRONT") return "Pièce d'identité recto";
  if (type === "IDENTITY_BACK") return "Pièce d'identité verso";
  if (type === "PROOF_OF_ADDRESS") return "Justificatif de domicile";
  return "Document support";
}

function statusLabel(status: KycStatus) {
  if (status === "PENDING") return "Action requise";
  if (status === "APPROVED") return "Validé";
  if (status === "REJECTED") return "Refusé";
  if (status === "EXPIRED") return "Expiré";
  return "Non requis";
}

function formatDate(value: string) {
  return new Intl.DateTimeFormat("fr-FR", { day: "2-digit", month: "2-digit", year: "numeric" }).format(new Date(value));
}
