/* =====================================================================
 * Stock d'habillement JSP : pièces numérotées par article et par taille.
 * L'attribution est déduite du tableau récapitulatif de l'année affichée.
 * ===================================================================== */

function StockAddForm({ onAdd }) {
  const [article, setArticle] = useState(STOCK_ARTICLES[0].key);
  const [taille, setTaille] = useState('');
  const [de, setDe] = useState('1');
  const [a, setA] = useState('');
  const isCasque = article === 'casque';
  const from = parseInt(de, 10);
  const to = parseInt(a || de, 10);
  const valid = (isCasque || taille.trim()) && from > 0 && to >= from && to - from < 200;

  return (
    <div className="grid grid-cols-2 items-end gap-3 lg:grid-cols-[1.3fr_1fr_0.7fr_0.7fr_auto]">
      <Field label="Article">
        <SelectInput placeholder={null} value={article} onChange={setArticle} options={STOCK_ARTICLES.map((f) => ({ value: f.key, label: f.label }))} />
      </Field>
      <Field label="Taille">
        <TextInput value={isCasque ? '' : taille} onChange={setTaille} disabled={isCasque} placeholder={isCasque ? '—' : 'ex : S, 14, 164'} />
      </Field>
      <Field label="Du n°">
        <NumberInput value={de} onChange={setDe} min="1" />
      </Field>
      <Field label="Au n°">
        <NumberInput value={a} onChange={setA} min="1" placeholder={de} />
      </Field>
      <Button
        className="col-span-2 lg:col-span-1"
        icon={Plus}
        disabled={!valid}
        onClick={() => {
          onAdd(article, isCasque ? '' : taille.trim().toUpperCase(), from, to);
          setA('');
        }}
      >
        Ajouter
      </Button>
    </div>
  );
}

const STOCK_CHIP = {
  dispo: 'border-emerald-400 bg-emerald-50 text-emerald-800 hover:bg-emerald-100',
  attribue: 'border-slate-700 bg-slate-700 text-white',
  conflit: 'border-red-600 bg-red-600 text-white',
  hs: 'border-slate-300 bg-slate-100 text-slate-400 line-through',
};

function JspStock({ jsps }) {
  const { jspStock, setJspStock, updateJspField, notify } = useApp();
  const [articleFilter, setArticleFilter] = useState('');
  const [onlyDispo, setOnlyDispo] = useState(false);
  const [deleteMode, setDeleteMode] = useState(false);
  const [conflit, setConflit] = useState(null);

  const { attributions, anomalies } = useMemo(() => stockAttributions(jsps), [jsps]);
  useEffect(() => {
    if (!conflit) return;
    const owners = attributions.get(stockKey(conflit.article, conflit.taille, conflit.numero)) || [];
    if (owners.length < 2) setConflit(null);
  }, [conflit, attributions]);
  const stockKeys = useMemo(() => new Set(jspStock.map((i) => stockKey(i.article, i.taille, i.numero))), [jspStock]);

  const statusOf = (item) => {
    const owners = attributions.get(stockKey(item.article, item.taille, item.numero)) || [];
    if (owners.length > 1) return { kind: 'conflit', owners };
    if (owners.length === 1) return { kind: 'attribue', owners };
    return { kind: item.hs ? 'hs' : 'dispo', owners };
  };

  const horsStock = useMemo(
    () =>
      [...attributions.entries()]
        .filter(([key]) => !stockKeys.has(key))
        .map(([key, owners]) => {
          const [article, taille, numero] = key.split('|');
          return { key, article, taille, numero: Number(numero), owners };
        }),
    [attributions, stockKeys],
  );

  const totals = useMemo(() => {
    const t = { total: jspStock.length, dispo: 0, attribue: 0, hs: 0, conflit: 0 };
    jspStock.forEach((item) => (t[statusOf(item).kind] += 1));
    return t;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [jspStock, attributions]);

  const groups = useMemo(() => {
    return STOCK_ARTICLES.filter((f) => !articleFilter || f.key === articleFilter)
      .map((field) => {
        const items = jspStock.filter((i) => i.article === field.key);
        const tailles = [...new Set(items.map((i) => i.taille))].sort(compareTailles).map((taille) => ({
          taille,
          items: items.filter((i) => i.taille === taille).sort((x, y) => x.numero - y.numero),
        }));
        return { field, tailles, count: items.length };
      })
      .filter((g) => g.count > 0);
  }, [jspStock, articleFilter]);

  const completer = () => {
    const { stock, added } = buildStockFromJsps(jsps, jspStock);
    setJspStock(stock);
    notify(added ? `${added} pièce${added > 1 ? 's' : ''} ajoutée${added > 1 ? 's' : ''} au stock` : 'Le stock est déjà à jour');
  };

  const addRange = (article, taille, from, to) => {
    const known = new Set(stockKeys);
    const added = [];
    for (let numero = from; numero <= to; numero += 1) {
      const key = stockKey(article, taille, numero);
      if (!known.has(key)) {
        known.add(key);
        added.push({ id: uid(), article, taille, numero, hs: false });
      }
    }
    setJspStock((s) => [...s, ...added]);
    notify(`${added.length} pièce${added.length > 1 ? 's' : ''} ajoutée${added.length > 1 ? 's' : ''}`);
  };

  const retirerDoublon = (owner) => {
    if (!conflit) return;
    const label = stockArticleOf(conflit.article).label;
    const code = stockCode(conflit.taille, conflit.numero);
    const nom = jspFullName(owner.jsp);
    if (!window.confirm(`Retirer ${label} ${code} de ${nom} ?\nLa case « ${owner.field.label} » sera vidée.`)) return;
    updateJspField(owner.jsp.id, owner.field.key, '');
    notify(`${label} ${code} retiré de ${nom}`);
  };

  const clickItem = (item, status) => {
    if (status.kind === 'conflit') {
      setConflit(item);
      return;
    }
    if (status.kind === 'attribue') return;
    if (deleteMode) {
      setJspStock((s) => s.filter((i) => i.id !== item.id));
      return;
    }
    setJspStock((s) => s.map((i) => (i.id === item.id ? { ...i, hs: !i.hs } : i)));
  };

  const exportCsv = () => {
    const rows = [
      ['Article', 'Taille', 'Numéro', 'Code', 'Statut', 'Attribué à'],
      ...STOCK_ARTICLES.flatMap((f) =>
        jspStock
          .filter((i) => i.article === f.key)
          .sort((x, y) => compareTailles(x.taille, y.taille) || x.numero - y.numero)
          .map((i) => {
            const st = statusOf(i);
            const labels = { dispo: 'Disponible', attribue: 'Attribué', conflit: 'Doublon', hs: 'Hors service' };
            return [f.label, i.taille, i.numero, stockCode(i.taille, i.numero), labels[st.kind], st.owners.map((o) => jspFullName(o.jsp)).join(', ')];
          }),
      ),
    ];
    downloadFile('stock-habillement-jsp.csv', toCsv(rows), 'text/csv;charset=utf-8');
  };

  return (
    <div className="space-y-5">
      <div className="grid grid-cols-2 gap-3 md:grid-cols-5">
        <StatCard label="Pièces en stock" value={totals.total} icon={Package} tone="slate" />
        <StatCard label="Disponibles" value={totals.dispo} icon={PackageCheck} tone="emerald" />
        <StatCard label="Attribuées" value={totals.attribue} icon={Shirt} tone="blue" />
        <StatCard label="Hors service" value={totals.hs} icon={X} tone="slate" />
        <StatCard label="Doublons" value={totals.conflit} icon={AlertTriangle} tone="red" />
      </div>

      <Card
        title="Gestion du stock"
        subtitle="Notation taille/numéro : S/10 = pièce n°10 de taille S"
        icon={Package}
        actions={
          <Fragment>
            <Button variant="secondary" icon={Download} onClick={exportCsv} disabled={!jspStock.length}>
              CSV
            </Button>
            <Button variant="dark" icon={RotateCcw} onClick={completer}>
              Compléter depuis le tableau
            </Button>
          </Fragment>
        }
      >
        <StockAddForm onAdd={addRange} />
      </Card>

      <div className="flex flex-wrap items-center justify-between gap-3">
        <div className="flex flex-wrap gap-2">
          <button type="button" onClick={() => setArticleFilter('')} className={cx('chip', !articleFilter ? TONE_SOLID.slate : 'chip-off')}>
            Tous
          </button>
          {STOCK_ARTICLES.map((f) => (
            <button
              key={f.key}
              type="button"
              onClick={() => setArticleFilter(articleFilter === f.key ? '' : f.key)}
              className={cx('chip', articleFilter === f.key ? TONE_SOLID.slate : 'chip-off')}
            >
              {f.label}
            </button>
          ))}
        </div>
        <div className="flex flex-wrap items-center gap-4">
          <Switch label="Disponibles uniquement" checked={onlyDispo} onChange={setOnlyDispo} />
          <Switch label="Mode suppression" checked={deleteMode} onChange={setDeleteMode} />
        </div>
      </div>

      <div className="flex flex-wrap items-center gap-4 text-xs text-slate-500">
        {[
          ['dispo', 'Disponible (clic : hors service)'],
          ['attribue', 'Attribuée à un JSP'],
          ['conflit', 'Doublon : cliquer pour choisir qui garde la pièce'],
          ['hs', 'Hors service'],
        ].map(([k, label]) => (
          <span key={k} className="flex items-center gap-1.5">
            <span className={cx('h-3 w-5 rounded border', STOCK_CHIP[k])} /> {label}
          </span>
        ))}
        {deleteMode && <Badge tone="red">Mode suppression : cliquer une pièce non attribuée la retire du stock</Badge>}
      </div>

      {groups.length === 0 ? (
        <EmptyState icon={Package} title="Stock vide" action={<Button icon={RotateCcw} onClick={completer}>Générer depuis le tableau</Button>}>
          Générez le stock à partir des tailles/numéros saisis dans le tableau, ou ajoutez des pièces manuellement.
        </EmptyState>
      ) : (
        <div className="grid gap-4 xl:grid-cols-2">
          {groups.map((g) => {
            const dispo = g.tailles.reduce((n, t) => n + t.items.filter((i) => statusOf(i).kind === 'dispo').length, 0);
            return (
              <Card key={g.field.key} title={g.field.label} icon={Shirt} actions={<Badge tone="emerald">{dispo} dispo / {g.count}</Badge>}>
                <div className="space-y-3">
                  {g.tailles.map((t) => {
                    const items = onlyDispo ? t.items.filter((i) => statusOf(i).kind === 'dispo') : t.items;
                    if (!items.length) return null;
                    return (
                      <div key={t.taille} className="flex gap-3">
                        <span className="w-14 shrink-0 pt-1 text-sm font-bold text-slate-700">{t.taille || 'N°'}</span>
                        <div className="flex flex-wrap gap-1.5">
                          {items.map((item) => {
                            const st = statusOf(item);
                            const owners = st.owners.map((o) => jspFullName(o.jsp)).join(', ');
                            return (
                              <button
                                key={item.id}
                                type="button"
                                onClick={() => clickItem(item, st)}
                                title={`${g.field.label} ${stockCode(item.taille, item.numero)}${owners ? ` — ${owners}` : st.kind === 'hs' ? ' — hors service' : ' — disponible'}`}
                                className={cx(
                                  'min-w-[3.25rem] rounded-md border px-2 py-1 text-xs font-semibold transition',
                                  STOCK_CHIP[st.kind],
                                  st.kind === 'conflit' && 'cursor-pointer ring-2 ring-red-300 hover:ring-white',
                                  deleteMode && (st.kind === 'dispo' || st.kind === 'hs') && 'ring-2 ring-red-300',
                                )}
                              >
                                {stockCode(item.taille, item.numero)}
                              </button>
                            );
                          })}
                        </div>
                      </div>
                    );
                  })}
                </div>
              </Card>
            );
          })}
        </div>
      )}

      {totals.conflit > 0 && (
        <Card title="Doublons à régler" subtitle="Une même pièce est attribuée à plusieurs JSP" icon={AlertTriangle}>
          <div className="flex flex-wrap gap-2">
            {jspStock
              .filter((item) => statusOf(item).kind === 'conflit')
              .map((item) => {
                const st = statusOf(item);
                return (
                  <button
                    key={item.id}
                    type="button"
                    onClick={() => setConflit(item)}
                    className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-left text-sm hover:border-red-400"
                  >
                    <span className="font-semibold text-red-800">
                      {stockArticleOf(item.article).label} {stockCode(item.taille, item.numero)}
                    </span>
                    <span className="mt-0.5 block text-xs text-red-700">{st.owners.map((o) => jspFullName(o.jsp)).join(' · ')}</span>
                  </button>
                );
              })}
          </div>
        </Card>
      )}

      {(horsStock.length > 0 || anomalies.length > 0) && (
        <div className="grid gap-4 lg:grid-cols-2">
          {horsStock.length > 0 && (
            <Card title="Attribuées mais absentes du stock" icon={Info} actions={<Button size="sm" onClick={completer}>Ajouter</Button>}>
              <ul className="space-y-1 text-sm">
                {horsStock.map((h) => (
                  <li key={h.key}>
                    <span className="font-semibold">{stockArticleOf(h.article).label} {stockCode(h.taille, h.numero)}</span> —{' '}
                    {h.owners.map((o) => jspFullName(o.jsp)).join(', ')}
                  </li>
                ))}
              </ul>
            </Card>
          )}
          {anomalies.length > 0 && (
            <Card title="Saisies non reconnues" subtitle="Format attendu : taille/numéro (ex : S/7)" icon={AlertTriangle}>
              <ul className="space-y-1 text-sm">
                {anomalies.map((a, i) => (
                  <li key={i}>
                    <span className="font-semibold">{jspFullName(a.jsp)}</span> — {a.field.label} : <span className="font-mono text-orange-700">« {a.raw} »</span>
                  </li>
                ))}
              </ul>
            </Card>
          )}
        </div>
      )}

      {conflit && (
        <Modal
          open
          size="sm"
          icon={AlertTriangle}
          title="Gérer le doublon"
          subtitle={`${stockArticleOf(conflit.article).label} ${stockCode(conflit.taille, conflit.numero)}`}
          onClose={() => setConflit(null)}
          footer={
            <Button variant="secondary" onClick={() => setConflit(null)}>
              Fermer
            </Button>
          }
        >
          <div className="space-y-3">
            <p className="text-sm text-slate-600">Cette pièce est attribuée à plusieurs JSP. Retirez-la de ceux qui ne doivent pas la garder.</p>
            {(attributions.get(stockKey(conflit.article, conflit.taille, conflit.numero)) || []).map((owner) => (
              <div key={owner.jsp.id + owner.field.key} className="flex items-center justify-between gap-3 rounded-lg border border-slate-200 px-3 py-2">
                <div>
                  <p className="font-semibold text-slate-800">{jspFullName(owner.jsp)}</p>
                  <p className="text-xs text-slate-500">
                    {owner.field.label} : {owner.jsp[owner.field.key]}
                  </p>
                </div>
                <Button size="sm" variant="danger" icon={Trash2} onClick={() => retirerDoublon(owner)}>
                  Retirer
                </Button>
              </div>
            ))}
          </div>
        </Modal>
      )}
    </div>
  );
}
