import { useEffect, useRef, useState } from 'react';
import {
  DOCUMENT_KIND_LABELS,
  DOCUMENT_KINDS,
  DOCUMENT_MAX_BYTES,
  type DocumentDto,
  type DocumentKind,
} from '@siop/shared';
import { useSetDocumentCorpus } from '@/api/assistant';
import {
  blobDocument,
  ouvrirDocument,
  telechargerDocument,
  useDeleteDocument,
  useDocuments,
  useUploadDocument,
} from '@/api/gestion';
import { Button } from '@/components/ui/button';

const CLASSE_TYPE: Partial<Record<DocumentKind, string>> = {
  CERTIFICATE: 'type-doc certificat',
  PHOTO: 'type-doc photo',
};

export function tailleLisible(octets: number): string {
  if (octets === 0) return '0 Ko';
  if (octets >= 1024 * 1024) return `${(octets / (1024 * 1024)).toFixed(1).replace('.', ',')} Mo`;
  return `${Math.max(1, Math.round(octets / 1024))} Ko`;
}

/** Aperçu réel des images : le fichier exige le jeton, donc pas de <img src>
 *  direct — on récupère le blob et on affiche une URL objet, révoquée au
 *  démontage. Les PDF gardent leur pictogramme (le navigateur les ouvre). */
function ApercuVignette({ doc }: { doc: DocumentDto }) {
  const estImage = doc.contentType.startsWith('image/');
  const [url, setUrl] = useState<string>();

  useEffect(() => {
    if (!estImage) return;
    let actif = true;
    let objet: string | undefined;
    blobDocument(doc.id)
      .then((blob) => {
        if (!actif) return;
        objet = URL.createObjectURL(blob);
        setUrl(objet);
      })
      .catch(() => {});
    return () => {
      actif = false;
      if (objet) URL.revokeObjectURL(objet);
    };
  }, [doc.id, estImage]);

  return (
    <button
      type="button"
      className="vignette"
      title={`Ouvrir ${doc.fileName}`}
      onClick={() => void ouvrirDocument(doc.id)}
    >
      {url ? <img src={url} alt={doc.fileName} /> : estImage ? '🖼' : '📄'}
    </button>
  );
}

/** Statut corpus (R5, D3) : lisible d'un coup d'œil, jamais ambigu. */
export function StatutCorpus({ doc }: { doc: DocumentDto }) {
  if (doc.contentType !== 'application/pdf') {
    return <span className="st exclu">image — non indexable</span>;
  }
  if (!doc.inCorpus) return <span className="st exclu">exclu du corpus</span>;
  if (!doc.indexedAt) return <span className="st encours">à indexer</span>;
  const quand = new Intl.DateTimeFormat('fr-FR', {
    day: 'numeric',
    month: 'short',
    hour: '2-digit',
    minute: '2-digit',
  }).format(new Date(doc.indexedAt));
  return (
    <span className="st ok">
      indexé · {quand} · {doc.chunkCount} extrait{doc.chunkCount > 1 ? 's' : ''}
    </span>
  );
}

/** Interrupteur d'inclusion au corpus (R5, D3) — PDF seulement, réversible.
 *  Une image non indexable s'affiche ÉTEINTE quel que soit l'état stocké :
 *  l'interrupteur montre la réalité du corpus, pas une colonne de base. */
export function InterrupteurCorpus({ doc }: { doc: DocumentDto }) {
  const bascule = useSetDocumentCorpus();
  return (
    <button
      type="button"
      role="switch"
      aria-checked={doc.contentType === 'application/pdf' && doc.inCorpus}
      aria-label={doc.inCorpus ? 'Exclure du corpus' : 'Inclure au corpus'}
      title={
        doc.contentType !== 'application/pdf'
          ? 'Seuls les PDF sont indexables'
          : doc.inCorpus
            ? 'Exclure du corpus (effectif à la prochaine réindexation)'
            : 'Inclure au corpus (effectif à la prochaine réindexation)'
      }
      className="interrupteur corpus"
      disabled={bascule.isPending || doc.contentType !== 'application/pdf'}
      onClick={() => bascule.mutate({ id: doc.id, inCorpus: !doc.inCorpus })}
    />
  );
}

export function VignetteDoc({
  doc,
  surSuppression,
}: {
  doc: DocumentDto;
  surSuppression?: (id: string) => void;
}) {
  return (
    <div className="doc">
      <ApercuVignette doc={doc} />
      <span className={CLASSE_TYPE[doc.kind] ?? 'type-doc'}>{DOCUMENT_KIND_LABELS[doc.kind]}</span>
      <b>{doc.fileName}</b>
      <span className="meta">
        {doc.assetReference ? `Asc. ${doc.assetReference} · ` : ''}
        {doc.workOrderReference ? `${doc.workOrderReference} · ` : ''}
        {tailleLisible(doc.size)} ·{' '}
        {new Intl.DateTimeFormat('fr-FR', { dateStyle: 'medium' }).format(new Date(doc.createdAt))}
        {doc.uploadedByName ? ` · ${doc.uploadedByName}` : ''}
      </span>
      <span style={{ display: 'flex', gap: 8 }}>
        <button
          type="button"
          onClick={() => void ouvrirDocument(doc.id)}
          style={{ color: 'var(--primaire)', fontWeight: 600, fontSize: 12.5 }}
        >
          Ouvrir
        </button>
        <button
          type="button"
          onClick={() => void telechargerDocument(doc.id, doc.fileName)}
          style={{ color: 'var(--primaire)', fontWeight: 600, fontSize: 12.5 }}
        >
          Télécharger
        </button>
        {surSuppression ? (
          <button
            type="button"
            onClick={() => {
              if (window.confirm(`Supprimer « ${doc.fileName} » ?`)) surSuppression(doc.id);
            }}
            style={{ color: 'var(--danger)', fontWeight: 600, fontSize: 12.5 }}
          >
            Supprimer
          </button>
        ) : null}
      </span>
    </div>
  );
}

/** Carte « Documents » des fiches OT / ascenseur — la même bibliothèque,
 *  filtrée sur la cible ; l'upload rattache automatiquement. */
export function CarteDocuments({
  cible,
  peutEditer,
}: {
  cible: { assetId: string } | { workOrderId: string };
  peutEditer: boolean;
}) {
  const { data: documents } = useDocuments(cible);
  const upload = useUploadDocument();
  const suppression = useDeleteDocument();
  const fichierRef = useRef<HTMLInputElement>(null);
  const [kind, setKind] = useState<DocumentKind>('workOrderId' in cible ? 'PHOTO' : 'NOTICE');

  const surFichier = (file: File | undefined) => {
    if (!file) return;
    if (file.size > DOCUMENT_MAX_BYTES) {
      window.alert('Fichier trop lourd (20 Mo max).');
      return;
    }
    upload.mutate({ file, kind, ...cible });
    if (fichierRef.current) fichierRef.current.value = '';
  };

  return (
    <div className="carte">
      <h2>Documents</h2>
      {documents?.length ? (
        <div className="docs" style={{ gridTemplateColumns: 'repeat(2, 1fr)' }}>
          {documents.map((d) => (
            <VignetteDoc
              key={d.id}
              doc={d}
              surSuppression={peutEditer ? (id) => suppression.mutate(id) : undefined}
            />
          ))}
        </div>
      ) : (
        <p className="text-encre-3">Aucun document rattaché.</p>
      )}
      {peutEditer ? (
        <div className="mt-3 flex items-center gap-2">
          <select
            aria-label="Type de document"
            value={kind}
            onChange={(e) => setKind(e.target.value as DocumentKind)}
            className="rounded-lg border border-bordure-forte bg-surface p-2 text-encre"
          >
            {DOCUMENT_KINDS.map((k) => (
              <option key={k} value={k}>{DOCUMENT_KIND_LABELS[k]}</option>
            ))}
          </select>
          <input
            ref={fichierRef}
            type="file"
            accept="application/pdf,image/jpeg,image/png"
            aria-label="Choisir un fichier"
            className="hidden"
            onChange={(e) => surFichier(e.target.files?.[0])}
          />
          <Button disabled={upload.isPending} onClick={() => fichierRef.current?.click()}>
            {upload.isPending ? 'Téléversement…' : 'Téléverser (PDF, JPG, PNG · 20 Mo)'}
          </Button>
        </div>
      ) : null}
      {upload.isError ? <p className="erreur-form">{upload.error.message}</p> : null}
    </div>
  );
}
