// Integrations — configure + test external API connections.
// Talks to /api/integrations. Secrets are masked on display; new values are
// accepted on save, mask placeholders (••••abcd) are preserved server-side.

function IntegrationsScreen() {
  const [list, setList] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [openSlug, setOpenSlug] = React.useState(null);
  const [toast, setToast] = React.useState(null);

  async function reload() {
    setLoading(true);
    const r = await fetch('/api/integrations', { credentials: 'same-origin' });
    if (r.status === 403) {
      setLoading(false);
      return;
    }
    const j = await r.json().catch(() => ({ integrations: [] }));
    setList(j.integrations || []);
    setLoading(false);
  }
  React.useEffect(() => { reload(); }, []);

  const current = list.find(i => i.slug === openSlug);

  const iconFor = {
    wordpress:   <IntegIco.wordpress/>,
    woocommerce: <IntegIco.woo/>,
    anthropic:   <IntegIco.anthropic/>,
    superfaktura:<IntegIco.invoice/>,
    goodwe:      <IntegIco.sun/>,
    clickup:     <IntegIco.task/>,
    microsoft365:<IntegIco.microsoft/>,
    smtp:        <Ico.mail/>,
  };

  // If we came back from an OAuth callback, toast + reload.
  React.useEffect(() => {
    const q = new URLSearchParams((location.hash.split('?')[1] || ''));
    if (q.get('connected')) {
      setToast({ kind: 'success', text: `Integrácia ${q.get('connected')} pripojená.` });
      history.replaceState(null, '', '#/integrations');
      // Reload list to pick up fresh status
      setTimeout(() => { reload(); }, 100);
    }
    const onMsg = (e) => {
      if (e.data && e.data.type && e.data.type.startsWith('oauth:') && e.data.ok) {
        setToast({ kind:'success', text: 'Účet pripojený.' });
        reload();
      }
    };
    window.addEventListener('message', onMsg);
    return () => window.removeEventListener('message', onMsg);
    // eslint-disable-next-line
  }, []);

  const statusChip = (s) => {
    const map = {
      connected:      <span className="chip green dot">Pripojené</span>,
      configured:     <span className="chip amber dot">Nastavené · netestované</span>,
      error:          <span className="chip red dot">Chyba</span>,
      not_connected:  <span className="chip gray dot">Nepripojené</span>,
    };
    return map[s] || map.not_connected;
  };

  return (
    <AppShell active="integrations" crumbs={['Administrácia', 'Integrácie']}>
      {toast && <Toast kind={toast.kind} onClose={() => setToast(null)}>{toast.text}</Toast>}

      <div className="page-head">
        <div>
          <h1>Integrácie</h1>
          <p>API kľúče a prepojenia na externé systémy. Tajné polia sú šifrované pri uložení.</p>
        </div>
        <div className="page-head-actions">
          <button className="btn" onClick={reload}><Ico.refresh/>Obnoviť</button>
        </div>
      </div>

      {loading ? (
        <div className="muted">Načítavam…</div>
      ) : list.length === 0 ? (
        <div className="card" style={{padding:20}}>
          <div className="muted">Nemáte oprávnenie na zobrazenie integrácií, alebo ešte nič nie je nastavené.</div>
        </div>
      ) : (
        <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(280px, 1fr))', gap:12}}>
          {list.map(i => (
            <button
              key={i.slug}
              onClick={() => setOpenSlug(i.slug)}
              className="mod-tile"
              style={{textAlign:'left', cursor:'pointer', background:'#fff', border:'1px solid var(--border)', color:'inherit', font:'inherit'}}
            >
              <div className="hstack">
                <div className="mod-ico">{iconFor[i.slug] || <Ico.sparkles/>}</div>
                <div style={{flex:1, minWidth:0}}>
                  <h4>{i.label}</h4>
                  <div className="small muted" style={{marginTop:2}}>{statusChip(i.status)}</div>
                </div>
                <Ico.chevRight style={{color:'var(--ink-400)'}}/>
              </div>
              <p style={{margin:0}}>{i.description}</p>
              {i.last_sync && (
                <div className="small muted">Naposledy úspešne: {new Date(i.last_sync * 1000).toLocaleString('sk-SK')}</div>
              )}
            </button>
          ))}
        </div>
      )}

      {current && (
        <IntegrationModal
          integration={current}
          onClose={() => setOpenSlug(null)}
          onSaved={() => { reload(); }}
          notify={(kind, text) => setToast({ kind, text })}
        />
      )}
    </AppShell>
  );
}

function IntegrationModal({ integration, onClose, onSaved, notify }) {
  const [values, setValues] = React.useState(() => {
    const init = {};
    for (const f of integration.fields) {
      // start blank for secret fields so user sees they can overwrite, and with current value for others
      init[f.key] = f.secret ? '' : (f.value || '');
    }
    return init;
  });
  const [busy, setBusy] = React.useState(null);
  const [testResult, setTestResult] = React.useState(null);

  function setField(k, v) {
    setValues(prev => ({ ...prev, [k]: v }));
    setTestResult(null);
  }

  async function save() {
    setBusy('save');
    // For secret fields left empty, omit from payload → backend preserves existing.
    const payload = {};
    for (const f of integration.fields) {
      if (f.secret && !values[f.key]) continue;
      payload[f.key] = values[f.key];
    }
    const r = await fetch(`/api/integrations/${integration.slug}`, {
      method: 'PATCH',
      credentials: 'same-origin',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ fields: payload }),
    });
    const j = await r.json().catch(() => ({}));
    setBusy(null);
    if (r.ok) {
      notify('success', 'Uložené.');
      onSaved();
    } else {
      notify('error', j.error || 'Nepodarilo sa uložiť.');
    }
  }

  async function test() {
    setBusy('test');
    setTestResult(null);
    // Save first so backend has the new values to test against
    const payload = {};
    for (const f of integration.fields) {
      if (f.secret && !values[f.key]) continue;
      payload[f.key] = values[f.key];
    }
    const save = await fetch(`/api/integrations/${integration.slug}`, {
      method: 'PATCH', credentials: 'same-origin',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ fields: payload }),
    });
    if (!save.ok) {
      setBusy(null);
      setTestResult({ ok: false, error: 'Nepodarilo sa uložiť pred testom.' });
      return;
    }
    const r = await fetch(`/api/integrations/${integration.slug}/test`, {
      method: 'POST', credentials: 'same-origin',
    });
    const j = await r.json().catch(() => ({ ok: false, error: 'Chyba servera' }));
    setBusy(null);
    setTestResult(j);
    if (j.ok) onSaved();
  }

  async function disconnect() {
    if (!confirm(`Odpojiť ${integration.label}? Uložené API údaje sa zmažú.`)) return;
    setBusy('disc');
    await fetch(`/api/integrations/${integration.slug}/disconnect`, {
      method: 'POST', credentials: 'same-origin',
    });
    setBusy(null);
    notify('success', 'Odpojené.');
    onSaved();
    onClose();
  }

  return (
    <Modal
      title={integration.label}
      width={560}
      onClose={onClose}
      footer={
        <>
          {integration.status !== 'not_connected' && (
            <button className="btn btn-danger btn-sm" onClick={disconnect} disabled={!!busy} style={{marginRight:'auto'}}>
              Odpojiť
            </button>
          )}
          <button className="btn" onClick={onClose} disabled={!!busy}>Zavrieť</button>
          <button className="btn btn-sm" onClick={test} disabled={!!busy}>
            {busy === 'test' ? 'Testujem…' : 'Otestovať spojenie'}
          </button>
          <button className="btn btn-primary btn-sm" onClick={save} disabled={!!busy}>
            {busy === 'save' ? 'Ukladám…' : 'Uložiť'}
          </button>
        </>
      }
    >
      <div className="small muted" style={{marginBottom:12}}>{integration.description}</div>

      {testResult && (
        <div className="auth-alert"
          style={testResult.ok
            ? {background:'var(--green-100)', color:'#135e37', borderColor:'rgba(42,157,95,0.3)'}
            : {}}
          role="alert">
          {testResult.ok ? <Ico.check/> : <Ico.dots/>}
          <span>{testResult.ok ? (testResult.message || 'Spojenie je platné.') : (testResult.error || 'Test zlyhal.')}</span>
        </div>
      )}

      {integration.oauth && (
        <OauthBlock
          integration={integration}
          hasClientCreds={!!(values.client_id && (values.client_secret || integration.fields.find(f => f.key === 'client_secret')?.has_value))}
          onBeforeConnect={async () => {
            // Persist any pending field edits so the server has client_id/secret to sign the auth URL.
            const payload = {};
            for (const f of integration.fields) {
              if (f.secret && !values[f.key]) continue;
              payload[f.key] = values[f.key];
            }
            const r = await fetch(`/api/integrations/${integration.slug}`, {
              method: 'PATCH', credentials: 'same-origin',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ fields: payload }),
            });
            return r.ok;
          }}
          onDisconnect={disconnect}
          notify={notify}
        />
      )}

      <div className="vstack" style={{gap:12}}>
        {integration.fields.map(f => (
          <div key={f.key} className="field">
            <label>{f.label}{f.required && <span style={{color:'var(--red-500)'}}> *</span>}</label>
            <input
              className="input"
              type={f.type === 'password' ? 'password' : f.type}
              value={values[f.key] ?? ''}
              onChange={e => setField(f.key, e.target.value)}
              placeholder={f.secret && f.has_value ? f.value : (f.placeholder || '')}
              autoComplete={f.type === 'password' ? 'new-password' : 'off'}
              spellCheck="false"
            />
            {f.secret && f.has_value && (
              <div className="small muted">Uložená hodnota: <span className="mono">{f.value}</span>. Pre zmenu zadajte novú.</div>
            )}
            {f.help && <div className="small muted">{f.help}</div>}
          </div>
        ))}
      </div>
    </Modal>
  );
}

function OauthBlock({ integration, hasClientCreds, onBeforeConnect, onDisconnect, notify }) {
  const o = integration.oauth;
  const [copied, setCopied] = React.useState(false);
  const [busy, setBusy] = React.useState(false);

  async function copyRedirect() {
    try { await navigator.clipboard.writeText(o.redirect_uri); setCopied(true); setTimeout(() => setCopied(false), 1500); }
    catch { notify && notify('error', 'Nepodarilo sa skopírovať.'); }
  }

  async function connect() {
    setBusy(true);
    const saved = await onBeforeConnect();
    setBusy(false);
    if (!saved) { notify && notify('error', 'Najprv uložte Client ID a Client secret.'); return; }
    // Open in same tab — Microsoft's login needs full redirect.
    window.location.href = `/api/integrations/${integration.slug}/oauth/start`;
  }

  return (
    <div className="card" style={{padding:12, background:'var(--blue-50)', border:'1px solid rgba(10,61,98,0.12)', marginBottom:14}}>
      <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, marginBottom:8}}>
        OAuth 2.0 · Authorization Code
      </div>
      <div className="field" style={{marginBottom:10}}>
        <label>Redirect URI (vložte do Azure → App registrations → Authentication)</label>
        <div className="hstack">
          <input className="input mono" readOnly value={o.redirect_uri}
                 onFocus={e => e.target.select()} style={{flex:1, fontSize:12}}/>
          <button type="button" className="btn btn-sm" onClick={copyRedirect} style={{whiteSpace:'nowrap'}}>
            {copied ? <><Ico.check/>Skopírované</> : <>Kopírovať</>}
          </button>
        </div>
        <div className="small muted">Platform type: <b>Web</b>. Povoľte <b>ID tokens</b> aj <b>Access tokens</b>.</div>
      </div>

      {o.connected ? (
        <div className="hstack" style={{background:'#fff', padding:10, borderRadius:6, border:'1px solid var(--border)'}}>
          <div style={{color:'#135e37'}}><Ico.check/></div>
          <div style={{flex:1, minWidth:0}}>
            <div style={{fontWeight:600}}>{o.account_display_name || o.account_upn}</div>
            <div className="small muted mono">{o.account_upn}</div>
          </div>
          <button type="button" className="btn btn-sm" onClick={connect} disabled={busy || !hasClientCreds}>
            {busy ? 'Otváram…' : 'Prepojiť iný účet'}
          </button>
        </div>
      ) : (
        <div className="hstack">
          <div className="small muted" style={{flex:1}}>
            Nie je pripojený žiadny Microsoft účet. {!hasClientCreds && <b>Najprv zadajte Client ID a Client secret a kliknite „Uložiť“.</b>}
          </div>
          <button type="button" className="btn btn-primary btn-sm" onClick={connect} disabled={busy || !hasClientCreds}>
            <IntegIco.microsoft/> {busy ? 'Otváram…' : 'Pripojiť cez Microsoft'}
          </button>
        </div>
      )}
    </div>
  );
}

// Brand / concept icons for integration tiles. Kept small, stroke-only where possible.
const IntegIco = {
  wordpress: (p={}) => <svg {...p} width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2c3 3 4 6 4 10s-1 7-4 10M12 2c-3 3-4 6-4 10s1 7 4 10"/></svg>,
  woo:       (p={}) => <svg {...p} width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 8h16l-2 9H6l-1-5H2"/><circle cx="9" cy="20" r="1.2"/><circle cx="16" cy="20" r="1.2"/></svg>,
  anthropic: (p={}) => <svg {...p} width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><path d="M13.5 3h3l5 18h-3l-1.2-4.4h-6.6L9.5 21h-3zm-1.1 8 2.6 0 -1.3-4.8zM3 3h3v18H3z"/></svg>,
  invoice:   (p={}) => <svg {...p} width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M6 2h10l4 4v16H6z"/><path d="M9 10h6M9 14h6M9 18h4"/></svg>,
  sun:       (p={}) => <svg {...p} width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>,
  task:      (p={}) => <svg {...p} width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="m8 12 3 3 5-6"/></svg>,
  microsoft: (p={}) => <svg {...p} width="18" height="18" viewBox="0 0 23 23" style={{verticalAlign:'-3px'}}><rect x="1" y="1" width="10" height="10" fill="#f25022"/><rect x="12" y="1" width="10" height="10" fill="#7fba00"/><rect x="1" y="12" width="10" height="10" fill="#00a4ef"/><rect x="12" y="12" width="10" height="10" fill="#ffb900"/></svg>,
};

Object.assign(window, { IntegrationsScreen });
