// ============================================================
// upload.jsx — Uploader drag&drop con classificazione AI REALE
// ============================================================
// FASE A (realizzazione): la classificazione del documento ora chiama
// davvero /api/ai/classify (multi-provider, legge i DocType dal DB) leggendo
// i byte del PDF. Se l'AI non è disponibile (nessuna chiave / errore provider)
// degrada con grazia all'euristica sul nome file (heuristicDocMeta), così il
// flusso di upload non si rompe mai.

function Uploader({
  compact = false,
  accept = '.pdf,application/pdf',
  title = 'Allega documenti',
  sub = 'Trascina PDF qui oppure clicca per selezionare. L\'AI classifica automaticamente tipologia e suggerisce il progetto.',
  onFiles,
  allowedTypes = ['offerta','capitolato','specifica','verbale','SAL','contratto','layout','checklist','rda'],
}) {
  const { seed, pushToast } = useStore();
  const inputRef = React.useRef(null);
  const [over, setOver] = React.useState(false);
  const [files, setFiles] = React.useState([]); // [{id,name,size,status,type,project,confidence,url}]

  function addFiles(list) {
    const arr = Array.from(list || []).filter(f => f.type === 'application/pdf' || /\.pdf$/i.test(f.name));
    if (!arr.length) {
      pushToast({ title: 'Solo file PDF', desc: 'Al momento accettiamo solo documenti PDF.', tone: 'warn' });
      return;
    }
    const staged = arr.map((f, i) => ({
      id: 'u_' + Date.now() + '_' + i,
      name: f.name,
      size: f.size,
      status: 'uploading',
      _file: f,
      url: URL.createObjectURL(f),
    }));
    setFiles(prev => [...staged, ...prev]);
    // Upload locale (preview) + classificazione AI REALE progressiva.
    staged.forEach((s, i) => {
      setTimeout(() => {
        setFiles(prev => prev.map(x => x.id === s.id ? { ...x, status: 'analyzing' } : x));
        classifyDocViaAi(s._file, allowedTypes, seed)
          .then((meta) => {
            setFiles(prev => prev.map(x => x.id === s.id ? { ...x, status: 'ready', ...meta } : x));
            const aiOk = meta.source === 'ai';
            pushToast({
              title: aiOk ? 'Documento classificato (AI)' : 'Documento classificato',
              desc: `${s.name} → ${meta.type} · ${Math.round((meta.confidence || 0) * 100)}%${aiOk ? '' : ' · euristica'}`,
              tone: aiOk ? 'ok' : 'warn',
            });
            if (onFiles) onFiles({ ...s, ...meta });
          });
      }, 350 + i * 160);
    });
  }

  function onDrop(e) {
    e.preventDefault(); setOver(false);
    addFiles(e.dataTransfer.files);
  }

  function remove(id) {
    setFiles(prev => prev.filter(f => f.id !== id));
  }

  return (
    <div className="uploader">
      <div
        className={`drop ${over ? 'over' : ''} ${compact ? 'compact' : ''}`}
        onClick={() => inputRef.current?.click()}
        onDragOver={(e) => { e.preventDefault(); setOver(true); }}
        onDragLeave={() => setOver(false)}
        onDrop={onDrop}
      >
        <div className="drop-ico"><Icon name="upload" size={compact ? 16 : 22}/></div>
        <div className="drop-text">
          <div className="drop-t">{title}</div>
          {!compact && <div className="drop-s">{sub}</div>}
        </div>
        <div className="drop-hint">
          <span className="kbd">PDF</span>
          <span style={{ marginLeft: 8, color: 'var(--text-3)', fontSize: 11 }}>max 20 MB</span>
        </div>
        <input ref={inputRef} type="file" accept={accept} multiple style={{ display: 'none' }}
          onChange={(e) => addFiles(e.target.files)} />
      </div>

      {files.length > 0 && (
        <div className="upload-list">
          {files.map((f) => <UploadedRow key={f.id} f={f} onRemove={() => remove(f.id)} />)}
        </div>
      )}
    </div>
  );
}

function UploadedRow({ f, onRemove }) {
  const statusChip = {
    uploading: <Chip kind="info" dot>upload</Chip>,
    analyzing: <Chip kind="ai">AI · classificazione</Chip>,
    ready: <Chip kind="ok" dot>pronto</Chip>,
    error: <Chip kind="err" dot>errore</Chip>,
  }[f.status];

  return (
    <div className="upload-row">
      <div className="ur-ico"><Icon name="file_pdf" size={14}/></div>
      <div className="ur-main">
        <div className="ur-name">{f.name}</div>
        <div className="ur-meta">
          <span className="mono">{fmtBytes(f.size)}</span>
          {f.status !== 'ready' && (
            <span style={{ marginLeft: 8, flex: 1, display: 'inline-block', height: 3, background: 'var(--bg-2)', borderRadius: 3, overflow: 'hidden', position: 'relative' }}>
              <span style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: f.status === 'uploading' ? '40%' : '75%', background: 'var(--accent)', animation: 'pulseBar 1.2s ease-in-out infinite' }} />
            </span>
          )}
          {f.status === 'ready' && (
            <>
              <Chip>{f.type}</Chip>
              {f.project && <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-2)' }}>→ {f.project}</span>}
              <span style={{ marginLeft: 'auto', fontSize: 10.5, color: 'var(--text-2)' }}>confidence {Math.round((f.confidence||0)*100)}%</span>
            </>
          )}
        </div>
      </div>
      <div className="ur-actions">
        {statusChip}
        {f.url && f.status === 'ready' && (
          <a className="btn ghost sm" href={f.url} target="_blank" rel="noreferrer"><Icon name="eye" size={12}/></a>
        )}
        <button className="btn ghost icon" onClick={onRemove}><Icon name="x" size={12}/></button>
      </div>
    </div>
  );
}

function fmtBytes(n) {
  if (!n) return '—';
  if (n < 1024) return n + ' B';
  if (n < 1024*1024) return (n/1024).toFixed(1) + ' KB';
  return (n/1024/1024).toFixed(2) + ' MB';
}

// ---- Classificazione AI reale -------------------------------------------------

function readLgsUserId() {
  try { const u = JSON.parse(localStorage.getItem('lgs.user')); return u?.id || ''; } catch { return ''; }
}

// Codifica i byte del file in base64 a chunk (evita stack overflow su PDF grandi).
async function fileToBase64(file) {
  const buf = await file.arrayBuffer();
  const bytes = new Uint8Array(buf);
  let binary = '';
  const CHUNK = 0x8000;
  for (let i = 0; i < bytes.length; i += CHUNK) {
    binary += String.fromCharCode.apply(null, bytes.subarray(i, i + CHUNK));
  }
  return btoa(binary);
}

// Classificazione AI reale: legge il PDF, chiama /api/ai/classify (multi-provider,
// DocType dal DB). In caso di chiave mancante / errore provider degrada
// all'euristica sul nome file. La proposta di progetto resta un match
// deterministico sul filename (non è "AI", è una regola esplicita).
async function classifyDocViaAi(file, allowed, seed) {
  const h = heuristicDocMeta(file?.name, allowed, seed);
  if (!file) return { ...h, source: 'euristica' };
  try {
    const base64 = await fileToBase64(file);
    const res = await fetch('/api/ai/classify', {
      method: 'POST',
      headers: { 'content-type': 'application/json', 'X-Actor-Persona-Id': readLgsUserId() },
      body: JSON.stringify({
        fileBase64: base64,
        mimeType: file.type || 'application/pdf',
        filename: file.name,
      }),
    });
    const j = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { ...h, source: 'euristica', aiError: j?.detail || j?.error || ('HTTP ' + res.status) };
    }
    const { docTypeCode, confidence, reasoning } = j.data || {};
    return {
      type: docTypeCode || h.type,
      project: h.project,
      confidence: typeof confidence === 'number' ? confidence : h.confidence,
      reasoning: reasoning || null,
      source: docTypeCode ? 'ai' : 'euristica',
    };
  } catch (err) {
    return { ...h, source: 'euristica', aiError: String(err?.message || err) };
  }
}

// Classificazione AI "raw" per i selector di upload reale (Documents D1): ritorna
// il docTypeCode del DB (o null se AI non disponibile / code non valido), così la UI
// può pre-fillare il dropdown DocType senza il fallback euristico (che usa label non-DB).
async function classifyDocReal(file) {
  if (!file) return { docTypeCode: null, confidence: 0, source: 'none' };
  try {
    const base64 = await fileToBase64(file);
    const res = await fetch('/api/ai/classify', {
      method: 'POST',
      headers: { 'content-type': 'application/json', 'X-Actor-Persona-Id': readLgsUserId() },
      body: JSON.stringify({ fileBase64: base64, mimeType: file.type || 'application/pdf', filename: file.name }),
    });
    const j = await res.json().catch(() => ({}));
    if (!res.ok) return { docTypeCode: null, confidence: 0, source: 'error', aiError: j?.detail || j?.error || ('HTTP ' + res.status) };
    const { docTypeCode, confidence, reasoning } = j.data || {};
    return { docTypeCode: docTypeCode || null, confidence: typeof confidence === 'number' ? confidence : 0, reasoning: reasoning || null, source: docTypeCode ? 'ai' : 'none' };
  } catch (err) {
    return { docTypeCode: null, confidence: 0, source: 'error', aiError: String(err?.message || err) };
  }
}

// Euristica di fallback — inferisce tipo + progetto dal nome file (deterministica,
// nessun valore casuale: confidence fissa bassa per segnalare "verifica manuale").
function heuristicDocMeta(name, allowed, seed) {
  const low = (name || '').toLowerCase();
  const rules = [
    { test: /offert|quot/i, type: 'offerta' },
    { test: /capitolat/i, type: 'capitolato' },
    { test: /specific|tech|datasheet/i, type: 'specifica' },
    { test: /verbal|minute|meeting|mom/i, type: 'verbale' },
    { test: /sal|advancement|progress/i, type: 'SAL' },
    { test: /contrat/i, type: 'contratto' },
    { test: /layout|plan|disegno/i, type: 'layout' },
    { test: /check|fat|sat/i, type: 'checklist' },
    { test: /rda|richiest/i, type: 'rda' },
  ];
  let type = 'specifica';
  for (const r of rules) { if (r.test.test(low)) { type = r.type; break; } }
  if (allowed && !allowed.includes(type)) type = allowed[0];

  // project match: cerca codice P-2026-NNN o parole chiave
  let project = '—';
  if (seed?.PROJECTS) {
    const m = (name || '').match(/P-\d{4}-\d{3}/i);
    if (m) {
      const found = seed.PROJECTS.find(p => p.id.toLowerCase() === m[0].toLowerCase());
      if (found) project = found.id;
    }
    if (project === '—') {
      const found = seed.PROJECTS.find(p => {
        const keys = (p.name + ' ' + p.category).toLowerCase().split(/\s+/).filter(x => x.length > 4);
        return keys.some(k => low.includes(k));
      });
      if (found) project = found.id;
    }
  }

  return { type, project, confidence: 0.5 };
}

Object.assign(window, { Uploader, classifyDocReal });
