// ============================================================
// customizing-sub-5.jsx
// FASE 6 Project Cockpit (sessione 106) — Customizing "Pesi salute progetto".
// ============================================================
//
// Singleton project_health_policy editor:
//  - 5 slider per i pesi (compliance/schedule/cost/governance/risks)
//  - 2 slider per le soglie (ok_min, warn_min)
//  - Warning live se la somma dei pesi non è 1.0 ±0.01
//  - Vincolo ok_min > warn_min (validato anche server-side)
//  - Bottone "🤖 Suggerisci pesi (AI)" → POST /ai-suggest, modal con
//    Corrente vs Suggerito + razionale + Accetta/Modifica/Scarta
//  - Save → PATCH /api/config/project-health-policy

function CustHealthPolicy() {
  const { user, pushToast } = useStore();
  const { useState, useEffect, useMemo } = React;

  const [policy, setPolicy] = useState(null);
  const [form, setForm] = useState(null);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState(null);
  const [suggesting, setSuggesting] = useState(false);
  const [suggestion, setSuggestion] = useState(null);
  // Quando l'utente ha cliccato "Accetta" sul modal, ricordiamo il razionale
  // + provider/model così la prossima Save manda `aiAcceptMeta` al PATCH e
  // l'audit_log riga ha action='ai_suggested_accepted' invece di 'update'.
  const [pendingAiAccept, setPendingAiAccept] = useState(null);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    fetch('/api/config/project-health-policy', {
      headers: { 'X-Actor-Persona-Id': user?.id || '' },
    })
      .then((r) => r.json())
      .then((j) => {
        if (cancelled) return;
        if (j?.data) {
          setPolicy(j.data);
          setForm({
            weights: { ...j.data.weights },
            thresholds: { ...j.data.thresholds },
          });
        }
      })
      .catch((e) => !cancelled && setError(String(e?.message || e)))
      .finally(() => !cancelled && setLoading(false));
    return () => {
      cancelled = true;
    };
  }, [user?.id]);

  const sumWeights = useMemo(() => {
    if (!form) return 0;
    return ['compliance', 'schedule', 'cost', 'governance', 'risks'].reduce(
      (a, d) => a + (form.weights[d] || 0),
      0,
    );
  }, [form]);

  const sumOk = Math.abs(sumWeights - 1.0) <= 0.01;
  const thresholdsOk = form ? form.thresholds.ok_min > form.thresholds.warn_min : false;
  const canSave = form && sumOk && thresholdsOk;

  const setWeight = (k, v) => setForm((f) => ({ ...f, weights: { ...f.weights, [k]: v } }));
  const setThr = (k, v) => setForm((f) => ({ ...f, thresholds: { ...f.thresholds, [k]: v } }));

  // Auto-normalize: redistribuisce in modo proporzionale gli altri pesi
  // mantenendo la somma a 1.0. Utility per UX più friendly.
  function normalizeNow() {
    if (!form) return;
    const dims = ['compliance', 'schedule', 'cost', 'governance', 'risks'];
    const sum = dims.reduce((a, d) => a + form.weights[d], 0);
    if (sum <= 0) return;
    const normalized = Object.fromEntries(dims.map((d) => [d, form.weights[d] / sum]));
    setForm((f) => ({ ...f, weights: normalized }));
  }

  async function handleSave() {
    if (!canSave || saving) return;
    setSaving(true);
    setError(null);
    try {
      const body = { ...form };
      if (pendingAiAccept) body.aiAcceptMeta = pendingAiAccept;
      const res = await fetch('/api/config/project-health-policy', {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json', 'X-Actor-Persona-Id': user?.id || '' },
        body: JSON.stringify(body),
      });
      const j = await res.json().catch(() => ({}));
      if (!res.ok) {
        const msg = j?.error === 'validation_error'
          ? `Validazione: ${(j.issues || []).map((i) => i.message).join(' · ')}`
          : (j?.error || `HTTP ${res.status}`);
        setError(msg);
        return;
      }
      if (j?.data) {
        setPolicy(j.data);
        setForm({ weights: { ...j.data.weights }, thresholds: { ...j.data.thresholds } });
      }
      // Consumed: il flag aiAcceptMeta si applica una sola volta per save.
      setPendingAiAccept(null);
      pushToast({
        title: 'Pesi salute aggiornati',
        desc: j?.changed === false ? 'Nessuna modifica' : 'Salvato. Audit registrato.',
        tone: 'ok',
      });
    } catch (e) {
      setError(String(e?.message || e));
    } finally {
      setSaving(false);
    }
  }

  async function handleSuggest(forceRefresh = false) {
    if (suggesting) return;
    setSuggesting(true);
    setError(null);
    try {
      const res = await fetch('/api/config/project-health-policy/ai-suggest', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Actor-Persona-Id': user?.id || '' },
        body: JSON.stringify({ forceRefresh }),
      });
      const j = await res.json().catch(() => ({}));
      if (!res.ok) {
        if (res.status === 429) {
          setError(`Quota AI esaurita (${j?.reason}). Reset tra ~${Math.round((j?.retryAfterSec || 0) / 60)} min.`);
        } else {
          setError(j?.error || `HTTP ${res.status}`);
        }
        return;
      }
      setSuggestion(j?.data || null);
      if (j?.data?.error) {
        pushToast({
          title: 'AI suggest fallito',
          desc: 'Pesi default applicati come fallback. Verifica le credenziali AI.',
          tone: 'warn',
        });
      }
    } catch (e) {
      setError(String(e?.message || e));
    } finally {
      setSuggesting(false);
    }
  }

  function acceptSuggestion(modifyMode = false) {
    if (!suggestion) return;
    setForm({
      weights: { ...suggestion.weights },
      thresholds: { ...suggestion.thresholds },
    });
    // Sia "Accetta" che "Modifica" → marcano il prossimo save come
    // ai_suggested_accepted (l'utente ha esplicitamente preso un suggerimento
    // AI come baseline, anche se ha poi rifinito i valori).
    setPendingAiAccept({
      rationale: suggestion.rationale,
      provider: suggestion.provider,
      model: suggestion.model,
    });
    setSuggestion(null);
    pushToast({
      title: modifyMode ? 'Pesi suggeriti caricati negli slider' : 'Suggerimenti applicati',
      desc: 'Clicca "Salva modifiche" per confermare in DB.',
      tone: 'ok',
    });
  }

  if (loading) {
    return <div style={{ padding: 14, color: 'var(--text-3)' }}>Caricamento policy…</div>;
  }
  if (!form) {
    return <div style={{ padding: 14, color: 'var(--err)' }}>Policy non disponibile.</div>;
  }

  return (
    <div className="col" style={{ gap: 14 }}>
      <div className="row" style={{ alignItems: 'center', gap: 8 }}>
        <div style={{ fontSize: 11.5, color: 'var(--text-2)', maxWidth: 560 }}>
          Singleton per tenant. I pesi sommano a 1.0 (±0.01) e bilanciano le 5 dimensioni dell'health score di
          progetto. Le soglie ok/warn determinano il colore del badge nel header di ProjectDetail.
        </div>
        <span className="spacer" />
        <Btn
          variant="ghost"
          size="sm"
          disabled={suggesting}
          onClick={() => handleSuggest(false)}
          data-action="ai-suggest-health-weights"
        >
          <Icon name="sparkle" size={11} /> {suggesting ? 'Analizzo portafoglio…' : 'Suggerisci pesi (AI)'}
        </Btn>
        <Btn variant="primary" size="sm" disabled={!canSave || saving} onClick={handleSave}>
          {saving ? 'Salvataggio…' : 'Salva modifiche'}
        </Btn>
      </div>

      {error && (
        <div
          style={{
            padding: 10,
            background: 'rgba(239,68,68,0.12)',
            border: '1px solid rgba(239,68,68,0.4)',
            borderRadius: 6,
            color: 'rgb(239,68,68)',
            fontSize: 11.5,
          }}
        >
          {error}
        </div>
      )}

      <div className="grid grid-2" style={{ gap: 14 }}>
        {/* PESI */}
        <div>
          <div className="eyebrow" style={{ marginBottom: 6 }}>Pesi sub-score (somma 1.0)</div>
          <div className="card" style={{ padding: 14 }}>
            {['compliance', 'schedule', 'cost', 'governance', 'risks'].map((d) => (
              <WeightSlider
                key={d}
                label={DIMENSION_LABEL[d]}
                desc={DIMENSION_DESC[d]}
                value={form.weights[d]}
                onChange={(v) => setWeight(d, v)}
              />
            ))}
            <div
              style={{
                marginTop: 10,
                padding: 10,
                background: sumOk ? 'rgba(34,197,94,0.10)' : 'rgba(245,158,11,0.12)',
                border: `1px solid ${sumOk ? 'rgba(34,197,94,0.35)' : 'rgba(245,158,11,0.4)'}`,
                borderRadius: 6,
                display: 'flex',
                alignItems: 'center',
                gap: 10,
                fontSize: 11.5,
              }}
            >
              <span style={{ color: sumOk ? 'rgb(34,197,94)' : 'rgb(245,158,11)', fontWeight: 600 }}>
                Σ = {sumWeights.toFixed(3)}
              </span>
              <span style={{ color: 'var(--text-2)' }}>
                {sumOk ? 'OK, somma valida' : 'Somma fuori range (richiesto 1.0 ±0.01)'}
              </span>
              <span className="spacer" />
              {!sumOk && (
                <Btn variant="ghost" size="xs" onClick={normalizeNow}>
                  Normalizza
                </Btn>
              )}
            </div>
          </div>
        </div>

        {/* THRESHOLDS */}
        <div>
          <div className="eyebrow" style={{ marginBottom: 6 }}>Soglie overall</div>
          <div className="card" style={{ padding: 14 }}>
            <div className="field">
              <label>
                ok_min ≥ <strong style={{ color: 'rgb(34,197,94)' }}>{form.thresholds.ok_min}</strong>
              </label>
              <input
                type="range"
                min={0}
                max={100}
                value={form.thresholds.ok_min}
                onChange={(e) => setThr('ok_min', Number(e.target.value))}
                style={{ width: '100%' }}
              />
              <div style={{ fontSize: 10.5, color: 'var(--text-3)' }}>Score ≥ {form.thresholds.ok_min} → badge verde.</div>
            </div>
            <div className="field">
              <label>
                warn_min ≥ <strong style={{ color: 'rgb(245,158,11)' }}>{form.thresholds.warn_min}</strong>
              </label>
              <input
                type="range"
                min={0}
                max={100}
                value={form.thresholds.warn_min}
                onChange={(e) => setThr('warn_min', Number(e.target.value))}
                style={{ width: '100%' }}
              />
              <div style={{ fontSize: 10.5, color: 'var(--text-3)' }}>
                {form.thresholds.warn_min} ≤ Score &lt; {form.thresholds.ok_min} → badge giallo. Score &lt; {form.thresholds.warn_min} → critical.
              </div>
            </div>
            {!thresholdsOk && (
              <div
                style={{
                  padding: 8,
                  background: 'rgba(239,68,68,0.10)',
                  border: '1px solid rgba(239,68,68,0.3)',
                  borderRadius: 6,
                  fontSize: 11,
                  color: 'rgb(239,68,68)',
                  marginTop: 6,
                }}
              >
                ok_min deve essere &gt; warn_min
              </div>
            )}
          </div>

          {/* AI metadata */}
          {policy?.aiSuggestedAt && (
            <div
              style={{
                marginTop: 14,
                padding: 12,
                background: 'rgba(99,102,241,0.08)',
                border: '1px solid rgba(99,102,241,0.3)',
                borderRadius: 6,
              }}
            >
              <div style={{ fontSize: 10, color: 'rgb(129,140,248)', fontWeight: 600, marginBottom: 4 }}>
                ✨ ULTIMO SUGGEST AI
              </div>
              <div style={{ fontSize: 11, color: 'var(--text-1)', lineHeight: 1.5, marginBottom: 6 }}>
                {policy.aiRationale}
              </div>
              <div style={{ fontSize: 10, color: 'var(--text-3)' }}>
                {new Date(policy.aiSuggestedAt).toLocaleString('it-IT')} via {policy.aiProvider}/{policy.aiModel}
              </div>
            </div>
          )}
        </div>
      </div>

      {suggestion && (
        <AiSuggestModal
          current={{ weights: policy?.weights || form.weights, thresholds: policy?.thresholds || form.thresholds }}
          suggestion={suggestion}
          onAccept={() => acceptSuggestion(false)}
          onModify={() => acceptSuggestion(true)}
          onDiscard={() => setSuggestion(null)}
          onForceRefresh={() => handleSuggest(true)}
        />
      )}
    </div>
  );
}

const DIMENSION_LABEL = {
  compliance: 'Compliance',
  schedule: 'Schedule (SPI)',
  cost: 'Cost (CPI)',
  governance: 'Governance',
  risks: 'Risks',
};

const DIMENSION_DESC = {
  compliance: 'Checklist documentale completata',
  schedule: 'Earned Value — rispetto delle date',
  cost: 'Earned Value — efficienza budget',
  governance: 'Step bloccati + SLA breach',
  risks: 'Anomalie aperte pesate per severità',
};

function WeightSlider({ label, desc, value, onChange }) {
  const pct = Math.round((value || 0) * 100);
  return (
    <div className="field" style={{ marginBottom: 12 }}>
      <label style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <span>{label}</span>
        <span
          style={{
            fontFamily: 'JetBrains Mono, monospace',
            fontSize: 12,
            color: 'var(--text-0)',
            fontWeight: 600,
          }}
        >
          {pct}%
        </span>
      </label>
      <input
        type="range"
        min={0}
        max={100}
        step={1}
        value={pct}
        onChange={(e) => onChange(Number(e.target.value) / 100)}
        style={{ width: '100%' }}
      />
      <div style={{ fontSize: 10.5, color: 'var(--text-3)', marginTop: 2 }}>{desc}</div>
    </div>
  );
}

function AiSuggestModal({ current, suggestion, onAccept, onModify, onDiscard, onForceRefresh }) {
  const dims = ['compliance', 'schedule', 'cost', 'governance', 'risks'];

  return (
    <div
      onClick={onDiscard}
      style={{
        position: 'fixed',
        inset: 0,
        background: 'rgba(0,0,0,0.6)',
        zIndex: 1000,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        padding: 20,
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          background: 'var(--bg-1)',
          border: '1px solid var(--line)',
          borderRadius: 12,
          maxWidth: 720,
          width: '100%',
          padding: 24,
          maxHeight: '90vh',
          overflowY: 'auto',
        }}
      >
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
          <h2 style={{ fontSize: 18, margin: 0 }}>
            <Icon name="sparkle" size={14} /> Suggerimento AI pesi salute
          </h2>
          <button onClick={onDiscard} style={{ background: 'none', border: 'none', color: 'var(--text-2)', fontSize: 22, cursor: 'pointer' }}>×</button>
        </div>

        {suggestion.error ? (
          <div
            style={{
              padding: 12,
              background: 'rgba(239,68,68,0.10)',
              border: '1px solid rgba(239,68,68,0.3)',
              borderRadius: 6,
              fontSize: 11.5,
              color: 'rgb(239,68,68)',
              marginBottom: 12,
            }}
          >
            AI ha restituito errore: <strong>{suggestion.error}</strong>. Sono mostrati i pesi default come fallback.
          </div>
        ) : null}

        {suggestion.cached && (
          <div
            style={{
              padding: 8,
              background: 'rgba(245,158,11,0.10)',
              border: '1px solid rgba(245,158,11,0.3)',
              borderRadius: 6,
              fontSize: 11,
              color: 'rgb(245,158,11)',
              marginBottom: 12,
              display: 'flex',
              alignItems: 'center',
              gap: 8,
            }}
          >
            <span>Risultato dalla cache (TTL 1h, portafoglio invariato).</span>
            <span className="spacer" />
            <Btn variant="ghost" size="xs" onClick={onForceRefresh}>Forza refresh</Btn>
          </div>
        )}

        <div style={{ marginBottom: 16 }}>
          <div className="eyebrow" style={{ marginBottom: 8 }}>Razionale</div>
          <div
            style={{
              padding: 12,
              background: 'rgba(99,102,241,0.08)',
              border: '1px solid rgba(99,102,241,0.3)',
              borderRadius: 6,
              fontSize: 12,
              color: 'var(--text-0)',
              lineHeight: 1.55,
            }}
          >
            {suggestion.rationale}
          </div>
          {suggestion.provider && (
            <div style={{ fontSize: 10, color: 'var(--text-3)', marginTop: 4 }}>
              via {suggestion.provider}/{suggestion.model}
              {suggestion.outputRetried && ' · retry parse OK alla seconda chiamata'}
            </div>
          )}
        </div>

        <div style={{ marginBottom: 16 }}>
          <div className="eyebrow" style={{ marginBottom: 8 }}>Confronto pesi</div>
          <table style={{ width: '100%', fontSize: 11.5, borderCollapse: 'collapse' }}>
            <thead>
              <tr style={{ borderBottom: '1px solid var(--line)' }}>
                <th style={{ textAlign: 'left', padding: 6 }}>Dimensione</th>
                <th style={{ textAlign: 'right', padding: 6, color: 'var(--text-2)' }}>Corrente</th>
                <th style={{ textAlign: 'right', padding: 6, color: 'rgb(129,140,248)' }}>Suggerito</th>
                <th style={{ textAlign: 'right', padding: 6, color: 'var(--text-2)' }}>Δ</th>
              </tr>
            </thead>
            <tbody>
              {dims.map((d) => {
                const cur = current.weights[d] || 0;
                const sug = suggestion.weights[d] || 0;
                const delta = sug - cur;
                return (
                  <tr key={d} style={{ borderBottom: '1px solid var(--line)' }}>
                    <td style={{ padding: 6 }}>{DIMENSION_LABEL[d]}</td>
                    <td style={{ padding: 6, textAlign: 'right', fontFamily: 'JetBrains Mono, monospace' }}>
                      {(cur * 100).toFixed(1)}%
                    </td>
                    <td style={{ padding: 6, textAlign: 'right', fontFamily: 'JetBrains Mono, monospace', color: 'rgb(129,140,248)', fontWeight: 600 }}>
                      {(sug * 100).toFixed(1)}%
                    </td>
                    <td
                      style={{
                        padding: 6,
                        textAlign: 'right',
                        fontFamily: 'JetBrains Mono, monospace',
                        color: Math.abs(delta) < 0.005 ? 'var(--text-3)' : delta > 0 ? 'rgb(34,197,94)' : 'rgb(239,68,68)',
                      }}
                    >
                      {delta >= 0 ? '+' : ''}
                      {(delta * 100).toFixed(1)}%
                    </td>
                  </tr>
                );
              })}
              <tr>
                <td style={{ padding: 6, fontWeight: 600 }}>Thresholds</td>
                <td colSpan={3} style={{ padding: 6, textAlign: 'right', fontSize: 11, color: 'var(--text-2)' }}>
                  ok_min: {current.thresholds.ok_min} → <strong style={{ color: 'rgb(129,140,248)' }}>{suggestion.thresholds.ok_min}</strong>{' · '}
                  warn_min: {current.thresholds.warn_min} → <strong style={{ color: 'rgb(129,140,248)' }}>{suggestion.thresholds.warn_min}</strong>
                </td>
              </tr>
            </tbody>
          </table>
        </div>

        <div style={{ marginBottom: 16, fontSize: 11, color: 'var(--text-2)' }}>
          Portafoglio analizzato: <strong>{suggestion.portfolio?.totalProjects}</strong> progetti vivi · budget medio{' '}
          <strong>{(suggestion.portfolio?.avgBudgetEur || 0).toLocaleString('it-IT')} EUR</strong> · anomalie aperte 90gg{' '}
          <strong>
            {(suggestion.portfolio?.openAnomaliesByLevel90d?.low || 0) +
              (suggestion.portfolio?.openAnomaliesByLevel90d?.medium || 0) +
              (suggestion.portfolio?.openAnomaliesByLevel90d?.high || 0) +
              (suggestion.portfolio?.openAnomaliesByLevel90d?.critical || 0)}
          </strong>{' '}
          · SLA breach 90gg <strong>{suggestion.portfolio?.slaBreaches90d}</strong>
        </div>

        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <Btn variant="ghost" size="sm" onClick={onDiscard}>Scarta</Btn>
          <Btn variant="ghost" size="sm" onClick={onModify}>Modifica (carica negli slider)</Btn>
          <Btn variant="primary" size="sm" onClick={onAccept}>Accetta</Btn>
        </div>
      </div>
    </div>
  );
}

window.CustHealthPolicy = CustHealthPolicy;
