/* cloudflare.jsx — Cloudflare deployment channel (the "everyone else" lane).
 *
 * AISO injects your JSON-LD at Cloudflare's edge with a tiny Worker (HTMLRewriter,
 * fail-open). No repo, no CMS, no file changes — the origin is never touched. Works for
 * any site proxied through Cloudflare (the orange cloud), whatever it's built with.
 *
 * Token storage: localStorage 'aiso:cloudflare:v1' = { token, account }
 * Per-domain injected schema: 'aiso:cf-schema:<domain>' = { [fixId]: code }  (accumulated)
 *
 * Token scopes (Account API Token → Custom):
 *   - Account · Workers Scripts: Edit
 *   - Account · Account Settings: Read
 *   - Zone · Workers Routes: Edit
 *   - Zone · Zone: Read
 */

const CF_KEY = 'aiso:cloudflare:v1';

function loadCf() {
  try { return JSON.parse(localStorage.getItem(CF_KEY) || '{}'); }
  catch { return {}; }
}
function saveCf(patch) {
  const next = { ...loadCf(), ...patch };
  localStorage.setItem(CF_KEY, JSON.stringify(next));
  window.dispatchEvent(new CustomEvent('aiso:cf-changed'));
  return next;
}
function clearCf() {
  localStorage.removeItem(CF_KEY);
  window.dispatchEvent(new CustomEvent('aiso:cf-changed'));
}

// Call the deploy endpoint. action: 'verify' | 'deploy' | 'remove'.
async function cfApi(action, { token, domain, schema } = {}) {
  const r = await fetch('/api/cloudflare-deploy', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ token, action, domain, schema }),
  });
  const d = await r.json().catch(() => ({}));
  if (!r.ok || d.error) throw new Error(d.hint || d.message || d.error || `Cloudflare HTTP ${r.status}`);
  return d;
}

// Accumulated schema for a domain: every CF-deployed fix's snippet lives here, keyed by
// fixId, so deploying a second fix doesn't drop the first. Returns the joined HTML blob.
function cfSchemaKey(domain) { return 'aiso:cf-schema:' + String(domain || '').replace(/^https?:\/\//, '').replace(/\/.*$/, '').toLowerCase(); }
function cfSchemaMap(domain) { try { return JSON.parse(localStorage.getItem(cfSchemaKey(domain)) || '{}'); } catch { return {}; } }
function cfAddSchema(domain, fixId, code) {
  const map = cfSchemaMap(domain);
  map[fixId] = code;
  localStorage.setItem(cfSchemaKey(domain), JSON.stringify(map));
  return Object.values(map).join('\n');
}
function cfBlob(domain) { return Object.values(cfSchemaMap(domain)).join('\n'); }

// High-level deploy used by the fix detail: accumulate this fix's snippet, push the whole
// blob to the edge. Returns the endpoint result.
async function cfDeployFix({ token, domain, fixId, code }) {
  const schema = cfAddSchema(domain, fixId, code);
  return cfApi('deploy', { token, domain, schema });
}

function CloudflareConnector({ onChange }) {
  const [state, setState] = React.useState(() => loadCf());
  const [token, setToken] = React.useState(state.token || '');
  const [reveal, setReveal] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    const onCh = () => setState(loadCf());
    window.addEventListener('aiso:cf-changed', onCh);
    return () => window.removeEventListener('aiso:cf-changed', onCh);
  }, []);

  async function connect() {
    if (!token.trim()) return;
    setBusy(true); setError(null);
    try {
      const res = await cfApi('verify', { token: token.trim() });
      saveCf({ token: token.trim(), account: res.account || '' });
      setState(loadCf());
      onChange?.();
    } catch (e) { setError(e.message); }
    finally { setBusy(false); }
  }
  function disconnect() { clearCf(); setState({}); setToken(''); onChange?.(); }

  const connected = !!state.token;

  return (
    <div className="gh-panel">
      <div className="gh-head">
        <div className="gh-logo" style={{ color: '#f6821f' }}>
          <svg width="24" height="24" viewBox="0 0 48 48" fill="currentColor"><path d="M36.4 28.6c.2-.7.1-1.4-.3-1.9-.4-.5-1-.8-1.7-.8l-13.2-.2c-.1 0-.2 0-.2-.1-.1-.1-.1-.2 0-.3.1-.2.2-.3.4-.3l13.3-.2c1.6-.1 3.3-1.4 3.9-2.9l.8-2c0-.1 0-.2 0-.3-1-4.4-4.9-7.7-9.6-7.7-4.3 0-8 2.8-9.3 6.7-.8-.6-1.9-.9-3-.8-2 .2-3.6 1.8-3.8 3.8 0 .5 0 1 .1 1.5C10.4 22.3 8 24.8 8 27.9c0 .3 0 .6.1.8 0 .1.1.2.3.2h24.3c.1 0 .3-.1.3-.2l.4-.1z"/></svg>
        </div>
        <div className="gh-head-text">
          <h3>Cloudflare <span style={{ fontSize: 11, fontWeight: 600, color: '#f6821f', background: 'rgba(246,130,31,0.12)', padding: '2px 7px', borderRadius: 999, marginLeft: 6, verticalAlign: 'middle' }}>any site</span></h3>
          <p>Works for any site behind Cloudflare. We inject your schema at the edge — no repo, no plugin, no file changes. Live in seconds.</p>
        </div>
      </div>

      {connected ? (
        <div className="gh-connected">
          <div className="gh-user">
            <div className="gh-logo" style={{ color: '#f6821f', width: 28, height: 28 }}>
              <svg width="20" height="20" viewBox="0 0 48 48" fill="currentColor"><path d="M36.4 28.6c.2-.7.1-1.4-.3-1.9-.4-.5-1-.8-1.7-.8l-13.2-.2c-.1 0-.2 0-.2-.1-.1-.1-.1-.2 0-.3.1-.2.2-.3.4-.3l13.3-.2c1.6-.1 3.3-1.4 3.9-2.9l.8-2c0-.1 0-.2 0-.3-1-4.4-4.9-7.7-9.6-7.7-4.3 0-8 2.8-9.3 6.7-.8-.6-1.9-.9-3-.8-2 .2-3.6 1.8-3.8 3.8 0 .5 0 1 .1 1.5C10.4 22.3 8 24.8 8 27.9c0 .3 0 .6.1.8 0 .1.1.2.3.2h24.3c.1 0 .3-.1.3-.2l.4-.1z"/></svg>
            </div>
            <div>
              <div className="gh-username">Cloudflare connected</div>
              <div className="gh-subtle">{state.account || 'Ready to ship to the edge'}</div>
            </div>
            <button className="btn-ghost" onClick={disconnect}>Disconnect</button>
          </div>
        </div>
      ) : (
        <div className="gh-connect">
          <div className="gh-instructions">
            <ol>
              <li>Open <a href="https://dash.cloudflare.com/profile/api-tokens" target="_blank" rel="noopener">Cloudflare → My Profile → API Tokens</a> → <strong>Create Token</strong> → <strong>Custom token</strong></li>
              <li>Permissions:
                <ul>
                  <li><strong>Account · Workers Scripts: Edit</strong></li>
                  <li><strong>Account · Account Settings: Read</strong></li>
                  <li><strong>Zone · Workers Routes: Edit</strong></li>
                  <li><strong>Zone · Zone: Read</strong></li>
                </ul>
              </li>
              <li>Account Resources: your account · Zone Resources: your site's zone</li>
              <li>Create, copy the token, paste it below.</li>
            </ol>
          </div>
          <div className="gh-input-row">
            <div className="kr-input-wrap" style={{ flex: 1 }}>
              <input
                type={reveal ? 'text' : 'password'}
                className="kr-input"
                value={token}
                onChange={(e) => setToken(e.target.value)}
                placeholder="Cloudflare API token…"
                autoComplete="off"
                spellCheck={false}
              />
              {token && Eye && (
                <button className="kr-reveal" onClick={() => setReveal(!reveal)}>{reveal ? <EyeOff /> : <Eye />}</button>
              )}
            </div>
            <button className="btn btn-primary" onClick={connect} disabled={busy || !token.trim()}>{busy ? 'Verifying…' : 'Connect'}</button>
          </div>
          {error && <div className="gh-error" style={{ marginTop: 10 }}>{error}</div>}
        </div>
      )}
    </div>
  );
}

window.cfLoad = loadCf;
window.cfSave = saveCf;
window.cfClear = clearCf;
window.cfApi = cfApi;
window.cfDeployFix = cfDeployFix;
window.cfBlob = cfBlob;
window.CloudflareConnector = CloudflareConnector;
