import { useState, type FormEvent } from 'react';
import { Link, useParams } from 'react-router-dom';
import {
  BILAN_FIELD_LABELS,
  REQUIRED_BILAN_FIELDS,
  WORK_ORDER_TYPE_LABELS,
  type BilanField,
  type BilanSuggestion,
  type WorkOrderDetail,
  type WorkOrderStatus,
} from '@siop/shared';
import { useSuggestBilan } from '@/api/assistant';
import {
  useCommentWorkOrder,
  usePatchChecklist,
  useReferenceValues,
  useSetAssignees,
  useTransitionWorkOrder,
  useUpsertReport,
  useWorkOrder,
} from '@/api/exploitation';
import { useAddLaborTime, useConsumePart, useParts } from '@/api/gestion';
import { useUsers } from '@/api/referentiel';
import { usePermissions } from '@/auth/use-permissions';
import { Avatar } from '@/components/avatar';
import { CarteDocuments } from '@/components/carte-documents';
import { Modale } from '@/components/ui/modale';
import { PrioriteOT, StatutOT } from '@/components/chips-ot';
import { Button } from '@/components/ui/button';
import { formatDateFr } from '@/lib/lieux';

const BOUTONS_TRANSITION: Record<WorkOrderStatus, { libelle: string; variant?: 'prim' | 'succes' | 'dangerLeger' | 'ghost' }> = {
  IN_PROGRESS: { libelle: 'Démarrer', variant: 'prim' },
  ON_HOLD: { libelle: 'En attente', variant: 'ghost' },
  DONE: { libelle: "Clôturer l'intervention", variant: 'succes' },
  CANCELLED: { libelle: 'Annuler', variant: 'dangerLeger' },
  OPEN: { libelle: 'Rouvrir' },
};

/** Écran 4 validé R0 (+ checklist maquette R2) : tout le carnet sur un écran. */
export default function PageFicheOT() {
  const { id } = useParams<{ id: string }>();
  const { data: ot } = useWorkOrder(id);
  const { can } = usePermissions();
  const transition = useTransitionWorkOrder(id ?? '');

  if (!ot) return null;
  const peutEditer = can('WORK_ORDERS', 'edit');
  const cloturable = ot.closureBlockers.length === 0;

  return (
    <>
      <div className="filajout">
        <Link to="/ot">Ordres de travail</Link> / {ot.reference}
      </div>
      <div className="entete-page">
        <h1>{ot.title}</h1>
        <StatutOT statut={ot.status} />
        <div className="actions">
          {peutEditer
            ? ot.allowedTransitions.map((cible) => {
                const bouton = BOUTONS_TRANSITION[cible];
                const bloquee = cible === 'DONE' && !cloturable;
                return (
                  <Button
                    key={cible}
                    variant={bouton.variant}
                    disabled={transition.isPending || bloquee}
                    title={bloquee ? ot.closureBlockers.join(' ; ') : undefined}
                    onClick={() => {
                      const commentaire =
                        cible === 'CANCELLED'
                          ? window.prompt('Motif d’annulation (visible dans l’activité) :') ?? undefined
                          : undefined;
                      if (cible === 'CANCELLED' && !commentaire) return;
                      transition.mutate({ to: cible, comment: commentaire });
                    }}
                  >
                    {bouton.libelle}
                  </Button>
                );
              })
            : null}
        </div>
      </div>
      {transition.isError ? (
        <p className="erreur-form" role="alert">{transition.error.message}</p>
      ) : null}
      <div className="grille-2">
        <CarteIntervention ot={ot} peutEditer={peutEditer} />
        <CarteActivite ot={ot} peutEditer={peutEditer} />
      </div>
      <div className="grille-2">
        <div className="flex flex-col gap-4">
          {ot.checklist.length > 0 ? <CarteChecklist ot={ot} peutEditer={peutEditer} /> : null}
          <CarteBilan ot={ot} peutEditer={peutEditer} />
        </div>
        <div className="flex flex-col gap-4">
          <CarteCouts ot={ot} peutEditer={peutEditer} />
          <CarteDocuments cible={{ workOrderId: ot.id }} peutEditer={peutEditer} />
        </div>
      </div>
    </>
  );
}

function CarteIntervention({ ot, peutEditer }: { ot: WorkOrderDetail; peutEditer: boolean }) {
  const { data: users } = useUsers();
  const assignation = useSetAssignees(ot.id);
  const [enAssignation, setEnAssignation] = useState(false);
  const techniciens = (users ?? []).filter(
    (u) => u.status === 'active' && u.role.name.startsWith('Technicien'),
  );

  return (
    <div className="carte">
      <h2>Intervention</h2>
      <dl className="infos">
        <dt>N°</dt>
        <dd className="num">{ot.reference} · {WORK_ORDER_TYPE_LABELS[ot.type]}</dd>
        <dt>Équipement</dt>
        <dd>
          <Link to={`/ascenseurs/${ot.assetId}`} style={{ color: 'var(--primaire)', fontWeight: 600 }}>
            Ascenseur {ot.assetReference}
          </Link>{' '}
          — {ot.siteName}
        </dd>
        <dt>Priorité</dt>
        <dd><PrioriteOT priorite={ot.priority} /></dd>
        <dt>Échéance</dt>
        <dd className="num">{formatDateFr(ot.dueDate)}</dd>
        <dt>Assignés</dt>
        <dd className="flex items-center gap-2">
          {ot.assignees.length ? (
            <>
              <span className="avatars">
                {ot.assignees.map((a) => (
                  <Avatar key={a.id} initials={a.initials} className="h-6 w-6 text-[10px]" />
                ))}
              </span>
              {ot.assignees.map((a) => a.displayName).join(', ')}
            </>
          ) : (
            '—'
          )}
          {peutEditer ? (
            <Button
              variant="ghost"
              className="px-2 py-1 text-[12px]"
              onClick={() => setEnAssignation((v) => !v)}
            >
              + Assigner
            </Button>
          ) : null}
        </dd>
        {ot.request ? (
          <>
            <dt>Demande liée</dt>
            <dd>
              <span className="num">{ot.request.reference}</span> — {ot.request.requesterLabel}
            </dd>
          </>
        ) : null}
      </dl>
      {enAssignation ? (
        <div className="mt-3 flex items-center gap-2">
          <select
            aria-label="Choisir un technicien"
            className="flex-1 rounded-lg border border-bordure-forte bg-surface p-2 text-encre"
            defaultValue=""
            onChange={(e) => {
              if (!e.target.value) return;
              assignation.mutate(
                { assigneeIds: [...new Set([...ot.assignees.map((a) => a.id), e.target.value])] },
                { onSuccess: () => setEnAssignation(false) },
              );
            }}
          >
            <option value="" disabled>Choisir un technicien…</option>
            {techniciens.map((t) => (
              <option key={t.id} value={t.id}>{t.displayName}</option>
            ))}
          </select>
          {ot.assignees.length ? (
            <Button
              variant="ghost"
              className="text-[12px]"
              onClick={() =>
                assignation.mutate({ assigneeIds: [] }, { onSuccess: () => setEnAssignation(false) })
              }
            >
              Tout retirer
            </Button>
          ) : null}
        </div>
      ) : null}
    </div>
  );
}

const KIND_LABELS: Record<string, string> = {
  CREATED: 'OT créé',
  GENERATED: 'Généré',
  FROM_REQUEST: 'Créé depuis une demande',
  STATUS_CHANGED: 'Changement d’état',
  ASSIGNED: 'Assignation',
  COMMENT: 'Commentaire',
};

function CarteActivite({ ot, peutEditer }: { ot: WorkOrderDetail; peutEditer: boolean }) {
  const commentaire = useCommentWorkOrder(ot.id);
  const surEnvoi = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const form = e.currentTarget;
    const message = String(new FormData(form).get('message') ?? '').trim();
    if (!message) return;
    commentaire.mutate(message, { onSuccess: () => form.reset() });
  };
  return (
    <div className="carte">
      <h2>Activité</h2>
      {peutEditer ? (
        <form onSubmit={surEnvoi} className="mb-3 flex gap-2">
          <input
            name="message"
            aria-label="Commenter"
            placeholder="Commenter…"
            className="flex-1 rounded-lg border border-bordure-forte bg-surface px-3 py-2 text-encre"
          />
          <Button type="submit" disabled={commentaire.isPending}>Publier</Button>
        </form>
      ) : null}
      <ul className="chrono">
        {ot.events.map((e) => (
          <li key={e.id} className="fait">
            {e.kind === 'COMMENT' ? (
              <>Commentaire {e.by ? <b>{e.by.displayName}</b> : null} : « {e.message} »</>
            ) : (
              <>
                <b>{KIND_LABELS[e.kind] ?? e.kind}</b>
                {e.message ? <> — {e.message}</> : null}
              </>
            )}
            <br />
            <span className="quand">
              {new Intl.DateTimeFormat('fr-FR', { dateStyle: 'medium', timeStyle: 'short' }).format(new Date(e.createdAt))}
              {e.by && e.kind !== 'COMMENT' ? ` · ${e.by.displayName}` : ''}
            </span>
          </li>
        ))}
      </ul>
    </div>
  );
}

function CarteChecklist({ ot, peutEditer }: { ot: WorkOrderDetail; peutEditer: boolean }) {
  const patch = usePatchChecklist(ot.id);
  const traitees = ot.checklist.filter((c) => c.state !== 'PENDING').length;
  return (
    <div className="carte">
      <h2>
        Checklist du mois{' '}
        <span style={{ color: 'var(--encre-3)', textTransform: 'none', letterSpacing: 0 }}>
          — {traitees} / {ot.checklist.length} traitées
        </span>
      </h2>
      {ot.checklist.map((item) => (
        <div className="check" key={item.id}>
          <button
            type="button"
            className={`coche ${item.state === 'DONE' ? 'ok' : item.state === 'NA' ? 'na' : ''}`}
            aria-label={`${item.label} — ${item.state === 'PENDING' ? 'marquer Fait (clic) ou N-A (double clic)' : 'remettre à faire'}`}
            disabled={!peutEditer || patch.isPending}
            onClick={() =>
              patch.mutate({
                itemId: item.id,
                state: item.state === 'PENDING' ? 'DONE' : item.state === 'DONE' ? 'NA' : 'PENDING',
              })
            }
          >
            {item.state === 'DONE' ? '✓' : item.state === 'NA' ? 'N-A' : ''}
          </button>
          {item.label}
          <span className="qui-fait">
            {item.doneBy
              ? `${item.doneBy.displayName.split(' ')[0]} · ${new Intl.DateTimeFormat('fr-FR', { timeStyle: 'short' }).format(new Date(item.doneAt!))}`
              : '—'}
          </span>
        </div>
      ))}
      {ot.checklist.some((c) => c.state === 'PENDING') ? (
        <p className="avertissement">
          ⚠ La clôture reste bloquée : chaque tâche doit être <b>Fait</b> ou <b>N-A</b>.
        </p>
      ) : null}
    </div>
  );
}

const fmtMad = new Intl.NumberFormat('fr-FR');

function minutesLisibles(minutes: number): string {
  const h = Math.floor(minutes / 60);
  const m = minutes % 60;
  return h ? `${h} h${m ? ` ${String(m).padStart(2, '0')}` : ''}` : `${m} min`;
}

/** Maquette R3 écran 4 : pièces à prix FIGÉ + main-d'œuvre à taux FIGÉ.
 *  Le coût suit l'OT pour toujours, même si prix et taux changent ensuite. */
function CarteCouts({ ot, peutEditer }: { ot: WorkOrderDetail; peutEditer: boolean }) {
  const [modale, setModale] = useState<'piece' | 'temps' | null>(null);
  const cloture = ot.status === 'DONE' || ot.status === 'CANCELLED';
  const { parts, labor, total } = ot.costs;

  return (
    <div className="carte">
      <h2>Pièces & main-d'œuvre</h2>
      {parts.length + labor.length === 0 ? (
        <p className="text-encre-3">Aucune consommation ni temps saisi.</p>
      ) : (
        <>
          {parts.map((p) => (
            <div className="item-liste" key={p.id}>
              <span className="ico">▣</span>
              {p.designation} × {p.quantity}
              <span className="fin num">{fmtMad.format(p.total)} MAD</span>
            </div>
          ))}
          {labor.map((l) => (
            <div className="item-liste" key={l.id}>
              <span className="ico">◔</span>
              {l.displayName} · {minutesLisibles(l.minutes)} × {fmtMad.format(l.hourlyRate)} MAD/h
              {l.note ? <span className="text-encre-3"> — {l.note}</span> : null}
              <span className="fin num">{fmtMad.format(l.total)} MAD</span>
            </div>
          ))}
          <div className="total">
            <span>Coût total de l'OT</span>
            <span className="num">{fmtMad.format(total)} MAD</span>
          </div>
        </>
      )}
      {peutEditer && !cloture ? (
        <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
          <Button onClick={() => setModale('piece')}>+ Consommer une pièce</Button>
          <Button onClick={() => setModale('temps')}>+ Saisir du temps</Button>
        </div>
      ) : null}
      {modale === 'piece' ? (
        <ModaleConsommation otId={ot.id} surFermeture={() => setModale(null)} />
      ) : null}
      {modale === 'temps' ? (
        <ModaleTemps otId={ot.id} surFermeture={() => setModale(null)} />
      ) : null}
    </div>
  );
}

function ModaleConsommation({ otId, surFermeture }: { otId: string; surFermeture: () => void }) {
  const { data: pieces } = useParts();
  const consommation = useConsumePart(otId);
  const [partId, setPartId] = useState('');
  const [quantite, setQuantite] = useState(1);
  const piece = (pieces ?? []).find((p) => p.id === partId);
  const stockApres = piece ? piece.stock - quantite : null;

  return (
    <Modale titre="Consommer une pièce" ouverte surFermeture={surFermeture}>
      <div className="flex flex-col gap-3">
        <div className="champ">
          <label htmlFor="cp-piece">Pièce *</label>
          <select id="cp-piece" value={partId} onChange={(e) => setPartId(e.target.value)}>
            <option value="">Sélectionner…</option>
            {(pieces ?? [])
              .filter((p) => p.isActive)
              .map((p) => (
                <option key={p.id} value={p.id} disabled={p.stock <= 0}>
                  {p.designation} — stock : {p.stock}
                </option>
              ))}
          </select>
        </div>
        <div className="champ">
          <label htmlFor="cp-qte">Quantité *</label>
          <input
            id="cp-qte"
            type="number"
            min={1}
            max={piece?.stock}
            className="num"
            style={{ width: 90 }}
            value={quantite || ''}
            onChange={(e) => setQuantite(Number(e.target.value))}
          />
        </div>
        {piece ? (
          <p className="note-douce">
            Prix figé à la consommation :{' '}
            <b className="num">
              {piece.lastUnitPrice != null ? `${fmtMad.format(piece.lastUnitPrice)} MAD/u` : 'aucun prix connu'}
            </b>{' '}
            (dernier prix d'achat). Le stock passera à <b className="num">{stockApres}</b>
            {stockApres != null && stockApres <= piece.threshold
              ? ' — sous le seuil, l’alerte s’allumera.'
              : '.'}
          </p>
        ) : null}
        {consommation.isError ? <p className="erreur-form">{consommation.error.message}</p> : null}
        <div className="pied">
          <Button onClick={surFermeture}>Annuler</Button>
          <Button
            variant="prim"
            disabled={!piece || quantite < 1 || (piece && quantite > piece.stock) || consommation.isPending}
            onClick={() =>
              consommation.mutate({ partId, quantity: quantite }, { onSuccess: surFermeture })
            }
          >
            Consommer (− stock, prix figé)
          </Button>
        </div>
      </div>
    </Modale>
  );
}

function ModaleTemps({ otId, surFermeture }: { otId: string; surFermeture: () => void }) {
  const saisie = useAddLaborTime(otId);
  const surEnvoi = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const donnees = new FormData(e.currentTarget);
    const heures = Number(donnees.get('heures') || 0);
    const minutes = Number(donnees.get('minutes') || 0);
    const totalMinutes = heures * 60 + minutes;
    if (totalMinutes < 1) return;
    saisie.mutate(
      {
        minutes: totalMinutes,
        note: String(donnees.get('note') ?? '').trim() || undefined,
      },
      { onSuccess: surFermeture },
    );
  };
  return (
    <Modale titre="Saisir du temps" ouverte surFermeture={surFermeture}>
      <form onSubmit={surEnvoi} className="flex flex-col gap-3">
        <div className="form-grille">
          <div className="champ">
            <label htmlFor="st-h">Heures</label>
            <input id="st-h" name="heures" type="number" min={0} max={24} defaultValue={1} className="num" />
          </div>
          <div className="champ">
            <label htmlFor="st-m">Minutes</label>
            <input id="st-m" name="minutes" type="number" min={0} max={59} defaultValue={0} className="num" />
          </div>
          <div className="champ pleine-l">
            <label htmlFor="st-note">Note (optionnelle)</label>
            <input id="st-note" name="note" placeholder="Ex. : réglage des coulisseaux" />
          </div>
        </div>
        <p className="note-douce">
          Le temps est valorisé au <b>taux horaire figé</b> de la personne connectée
          (géré dans Personnes) — il ne bougera plus, même si le taux change.
        </p>
        {saisie.isError ? <p className="erreur-form">{saisie.error.message}</p> : null}
        <div className="pied">
          <Button onClick={surFermeture}>Annuler</Button>
          <Button type="submit" variant="prim" disabled={saisie.isPending}>Enregistrer</Button>
        </div>
      </form>
    </Modale>
  );
}

const CHAMPS_BILAN: { champ: BilanField; cle: keyof NonNullable<WorkOrderDetail['report']> & string; dto: string }[] = [
  { champ: 'DOOR_STATE', cle: 'doorState', dto: 'doorStateId' },
  { champ: 'CABIN_POSITION', cle: 'cabinPosition', dto: 'cabinPositionId' },
  { champ: 'ANOMALY', cle: 'anomaly', dto: 'anomalyId' },
  { champ: 'EXTERNAL_CAUSE', cle: 'externalCause', dto: 'externalCauseId' },
  { champ: 'ACTION_TAKEN', cle: 'actionTaken', dto: 'actionTakenId' },
  { champ: 'COMPONENT_CONCERNED', cle: 'componentConcerned', dto: 'componentConcernedId' },
];

/** Écran 3 des maquettes R5 : décrire la panne en français libre → l'IA
 *  propose des codes EXISTANTS avec justification et confiance (D1). Rien ne
 *  s'écrit sans le geste humain : « Appliquer » est ce geste — chaque champ
 *  appliqué garde son liseré « suggéré » jusqu'à modification manuelle. */
function ZoneSuggestion({
  surAppliquer,
  appliqueTout,
}: {
  surAppliquer: (s: BilanSuggestion) => void;
  appliqueTout: (liste: BilanSuggestion[]) => void;
}) {
  const suggerer = useSuggestBilan();
  const [description, setDescription] = useState('');
  const [masquees, setMasquees] = useState(false);
  const suggestions = masquees ? [] : (suggerer.data?.suggestions ?? []);

  return (
    <>
      <div className="champ-b" style={{ gridColumn: '1 / -1' }}>
        <label htmlFor="sug-description">Décrire pour suggérer (optionnel)</label>
        <textarea
          id="sug-description"
          className="zone-libre"
          placeholder="Décrivez la panne et ce que vous avez fait — l'IA proposera les codes du bilan…"
          value={description}
          maxLength={2000}
          onChange={(e) => setDescription(e.target.value)}
        />
        <div className="actions-sug">
          <Button
            variant="prim"
            disabled={description.trim().length < 10 || suggerer.isPending}
            onClick={() => {
              setMasquees(false);
              suggerer.mutate({ description: description.trim() });
            }}
          >
            {suggerer.isPending ? 'Analyse…' : '✨ Suggérer les codes'}
          </Button>
          <span style={{ fontSize: 11.5, color: 'var(--encre-3)', alignSelf: 'center' }}>
            La description n'écrit rien toute seule — vous appliquez, ou pas.
          </span>
        </div>
        {suggerer.isError ? (
          <p className="erreur-form" role="alert">{suggerer.error.message}</p>
        ) : null}
        {suggerer.isSuccess && suggestions.length === 0 && !masquees ? (
          <p style={{ fontSize: 12.5, color: 'var(--encre-2)' }}>
            Aucun code assez proche de cette description — l'IA ne devine pas : choisissez dans les
            sélecteurs.
          </p>
        ) : null}
        {suggestions.length > 0 ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 8 }}>
            {suggestions.map((s) => (
              <div className="suggestion" key={s.field}>
                <span className="ia">✨</span>
                <div>
                  <b>
                    {BILAN_FIELD_LABELS[s.field]} → « {s.label} »
                  </b>
                  <div className="just">
                    {s.similarReports > 0
                      ? `${s.similarReports} bilan${s.similarReports > 1 ? 's' : ''} similaire${s.similarReports > 1 ? 's' : ''} sur ce parc`
                      : 'proche de votre description'}
                  </div>
                </div>
                <span className="confiance">
                  confiance {s.confidence === 'HIGH' ? 'forte' : 'moyenne'}
                </span>
                <Button onClick={() => surAppliquer(s)}>Appliquer</Button>
              </div>
            ))}
            <div className="actions-sug">
              <Button variant="prim" onClick={() => appliqueTout(suggestions)}>
                Appliquer les {suggestions.length} (pré-remplir)
              </Button>
              <Button onClick={() => setMasquees(true)}>Ignorer</Button>
            </div>
          </div>
        ) : null}
      </div>
    </>
  );
}

function CarteBilan({ ot, peutEditer }: { ot: WorkOrderDetail; peutEditer: boolean }) {
  const { data: valeurs } = useReferenceValues();
  const maj = useUpsertReport(ot.id);
  const bloqueurBilan = ot.closureBlockers.find((b) => b.includes('bilan'));
  const [suggeres, setSuggeres] = useState<Set<BilanField>>(new Set());
  const modifiable = peutEditer && ot.status !== 'DONE' && ot.status !== 'CANCELLED';

  const appliquer = (liste: BilanSuggestion[]) => {
    const corps = Object.fromEntries(
      liste.map((s) => [CHAMPS_BILAN.find((c) => c.champ === s.field)!.dto, s.valueId]),
    );
    maj.mutate(corps, {
      onSuccess: () =>
        setSuggeres((avant) => new Set([...avant, ...liste.map((s) => s.field)])),
    });
  };

  return (
    <div className="carte">
      <h2>
        Bilan d'intervention{' '}
        <span style={{ color: 'var(--encre-3)', textTransform: 'none', letterSpacing: 0 }}>
          — requis pour clôturer
        </span>
      </h2>
      {modifiable ? (
        <ZoneSuggestion
          surAppliquer={(s) => appliquer([s])}
          appliqueTout={appliquer}
        />
      ) : null}
      <div className="bilan">
        {CHAMPS_BILAN.map(({ champ, cle, dto }) => {
          const options = (valeurs ?? []).filter((v) => v.field === champ && v.isActive);
          const valeur = ot.report?.[cle as 'doorState'] ?? null;
          const requis = REQUIRED_BILAN_FIELDS.includes(champ);
          return (
            <div className="champ-b" key={champ} data-suggere={suggeres.has(champ) || undefined}>
              <label htmlFor={`bilan-${champ}`}>
                {BILAN_FIELD_LABELS[champ]} {requis ? <em>*</em> : null}
              </label>
              <select
                id={`bilan-${champ}`}
                disabled={!peutEditer || maj.isPending || ot.status === 'DONE' || ot.status === 'CANCELLED'}
                value={valeur?.id ?? ''}
                onChange={(e) => {
                  // choix manuel : le liseré « suggéré » n'a plus lieu d'être
                  setSuggeres((avant) => {
                    const suite = new Set(avant);
                    suite.delete(champ);
                    return suite;
                  });
                  maj.mutate({ [dto]: e.target.value || null });
                }}
              >
                <option value="">Sélectionner…</option>
                {options.map((o) => (
                  <option key={o.id} value={o.id}>{o.label}</option>
                ))}
              </select>
            </div>
          );
        })}
      </div>
      {bloqueurBilan && ot.status !== 'DONE' && ot.status !== 'CANCELLED' ? (
        <p className="avertissement">⚠ {bloqueurBilan} — la clôture restera bloquée.</p>
      ) : null}
      {maj.isError ? <p className="erreur-form" role="alert">{maj.error.message}</p> : null}
    </div>
  );
}
