/* global React, Icon, IconBtn, useReceiveFrom, SendToButton, copyText, db */
const { useState, useEffect, useMemo, useCallback } = React;

// ============================================================
// Encode / decode helpers
// ============================================================

// UTF-8-safe base64
function b64Encode(text) {
  try {
    return btoa(String.fromCharCode(...new TextEncoder().encode(text)));
  } catch (e) { return ''; }
}
function b64Decode(text) {
  try {
    const clean = text.replace(/\s+/g, '');
    const bin = atob(clean);
    const bytes = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
    return new TextDecoder('utf-8', { fatal: false }).decode(bytes);
  } catch (e) { return null; }
}

// base64url (used in JWT) — replace +/= with -/_/none
function b64urlDecode(s) {
  s = s.replace(/-/g, '+').replace(/_/g, '/');
  while (s.length % 4) s += '=';
  return b64Decode(s);
}

// JWT decoder
function decodeJWT(token) {
  if (!token || !token.trim()) return null;
  const parts = token.trim().split('.');
  if (parts.length !== 3) {
    return { error: 'A JWT must have three parts separated by dots (header.payload.signature)' };
  }
  const [h, p, s] = parts;
  const headerRaw = b64urlDecode(h);
  const payloadRaw = b64urlDecode(p);
  let header = null, payload = null, headerErr = null, payloadErr = null;
  try { header = headerRaw ? JSON.parse(headerRaw) : null; }
  catch (e) { headerErr = 'Header is not valid JSON: ' + e.message; }
  try { payload = payloadRaw ? JSON.parse(payloadRaw) : null; }
  catch (e) { payloadErr = 'Payload is not valid JSON: ' + e.message; }
  return { header, payload, signature: s, headerErr, payloadErr, raw: { header: h, payload: p, signature: s } };
}

// ============================================================
// Main Encode tool — tabbed
// ============================================================
const ENCODE_TABS = [
  { id: 'jwt',    label: 'JWT decoder', icon: 'token' },
  { id: 'base64', label: 'Base64',      icon: 'data_array' },
  { id: 'url',    label: 'URL encode',  icon: 'link' },
];

function EncodeTool() {
  const [tab, setTab] = useState('jwt');

  // Allow receiving via send-to
  useReceiveFrom('encode', (payload) => {
    if (!payload?.text) return;
    // heuristic: if it looks like JWT, switch to JWT tab
    const t = payload.text.trim();
    if (/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*$/.test(t)) setTab('jwt');
  });

  return (
    <div className="tool encode-tool">
      <div className="encode-tabs">
        {ENCODE_TABS.map(t => (
          <button
            key={t.id}
            className={`encode-tab ${tab === t.id ? 'is-active' : ''}`}
            onClick={() => setTab(t.id)}
          >
            <Icon name={t.icon} />
            <span>{t.label}</span>
          </button>
        ))}
      </div>
      <div className="encode-body">
        {tab === 'jwt'    && <JwtPanel />}
        {tab === 'base64' && <Base64Panel />}
        {tab === 'url'    && <UrlPanel />}
      </div>
    </div>
  );
}

// ============================================================
// JWT decoder panel
// ============================================================
function JwtPanel() {
  const SAMPLE = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzMwMDAwMDAwLCJleHAiOjE5OTk5OTk5OTl9.4lZ5J0Gv8R8sFM9bC8jcfTQK7QSQT2j2gqkRZL_5K94';
  const [token, setToken] = useState('');
  const decoded = useMemo(() => decodeJWT(token), [token]);
  const [copiedKey, setCopiedKey] = useState(null);

  const copyJson = async (key, obj) => {
    const ok = await copyText(JSON.stringify(obj, null, 2));
    if (ok) {
      setCopiedKey(key);
      setTimeout(() => setCopiedKey(null), 1500);
    }
  };
  const copyRaw = async (key, val) => {
    const ok = await copyText(val);
    if (ok) {
      setCopiedKey(key);
      setTimeout(() => setCopiedKey(null), 1500);
    }
  };

  // Pretty-print claims with semantic highlights for known ones
  const renderClaims = (obj) => {
    if (!obj) return null;
    const knownTime = new Set(['exp', 'iat', 'nbf', 'auth_time']);
    const entries = Object.entries(obj);
    return (
      <div className="enc-claims">
        {entries.map(([k, v]) => {
          let extra = null;
          if (knownTime.has(k) && typeof v === 'number') {
            const d = new Date(v * 1000);
            const isExp = k === 'exp';
            const expired = isExp && d.getTime() < Date.now();
            extra = (
              <div className={`enc-claim-extra ${expired ? 'is-expired' : ''}`}>
                {d.toLocaleString()} {isExp && (expired ? '· expired' : '· valid')}
              </div>
            );
          }
          return (
            <div key={k} className="enc-claim-row">
              <div className="enc-claim-key">{k}</div>
              <div className="enc-claim-val">
                <code>{typeof v === 'string' ? v : JSON.stringify(v)}</code>
                {extra}
              </div>
            </div>
          );
        })}
      </div>
    );
  };

  return (
    <div className="enc-panel">
      <div className="enc-input-wrap">
        <div className="enc-input-head">
          <span>Token</span>
          <div style={{ flex: 1 }} />
          <button className="lh-chip" onClick={() => setToken(SAMPLE)}>
            <Icon name="science" />Sample
          </button>
          <button className="lh-chip" onClick={() => setToken('')}>
            <Icon name="close" />Clear
          </button>
        </div>
        <textarea
          className="enc-input"
          placeholder="Paste a JWT here (header.payload.signature)…"
          value={token}
          onChange={e => setToken(e.target.value)}
          spellCheck={false}
        />
        {token && (
          <div className="enc-jwt-pieces">
            <span className="enc-piece part-h">{decoded?.raw?.header || ''}</span>
            <span className="enc-piece-sep">.</span>
            <span className="enc-piece part-p">{decoded?.raw?.payload || ''}</span>
            <span className="enc-piece-sep">.</span>
            <span className="enc-piece part-s">{decoded?.raw?.signature || ''}</span>
          </div>
        )}
      </div>

      {!token ? (
        <div className="lh-empty">
          <Icon name="token" />
          <div className="title">Paste a JWT to decode</div>
          <div className="sub">Decoding happens locally — no network calls.</div>
        </div>
      ) : decoded?.error ? (
        <div className="enc-error">
          <Icon name="error" />
          <span>{decoded.error}</span>
        </div>
      ) : (
        <div className="enc-jwt-grid">
          <div className="enc-card part-h">
            <div className="enc-card-head">
              <span className="enc-card-tag">Header</span>
              <div style={{ flex: 1 }} />
              {decoded.header && (
                <button className="lh-chip" onClick={() => copyJson('header', decoded.header)}>
                  <Icon name={copiedKey === 'header' ? 'check' : 'content_copy'} />
                  {copiedKey === 'header' ? 'Copied' : 'Copy JSON'}
                </button>
              )}
            </div>
            {decoded.headerErr ? (
              <pre className="enc-card-pre">{decoded.headerErr}</pre>
            ) : (
              <pre className="enc-card-pre">{JSON.stringify(decoded.header, null, 2)}</pre>
            )}
          </div>

          <div className="enc-card part-p">
            <div className="enc-card-head">
              <span className="enc-card-tag">Payload</span>
              <div style={{ flex: 1 }} />
              {decoded.payload && (
                <button className="lh-chip" onClick={() => copyJson('payload', decoded.payload)}>
                  <Icon name={copiedKey === 'payload' ? 'check' : 'content_copy'} />
                  {copiedKey === 'payload' ? 'Copied' : 'Copy JSON'}
                </button>
              )}
            </div>
            {decoded.payloadErr ? (
              <pre className="enc-card-pre">{decoded.payloadErr}</pre>
            ) : decoded.payload && Object.keys(decoded.payload).length > 0 ? (
              renderClaims(decoded.payload)
            ) : (
              <pre className="enc-card-pre">{JSON.stringify(decoded.payload, null, 2)}</pre>
            )}
          </div>

          <div className="enc-card part-s">
            <div className="enc-card-head">
              <span className="enc-card-tag">Signature</span>
              <div style={{ flex: 1 }} />
              {decoded.signature && (
                <button className="lh-chip" onClick={() => copyRaw('signature', decoded.signature)}>
                  <Icon name={copiedKey === 'signature' ? 'check' : 'content_copy'} />
                  {copiedKey === 'signature' ? 'Copied' : 'Copy'}
                </button>
              )}
              <span className="enc-note">Cannot verify without key</span>
            </div>
            <pre className="enc-card-pre signature">{decoded.signature || '(none)'}</pre>
          </div>
        </div>
      )}
    </div>
  );
}

// ============================================================
// Base64 panel
// ============================================================
function Base64Panel() {
  const [mode, setMode] = useState('encode'); // 'encode' | 'decode'
  const [input, setInput] = useState('');
  const [output, error] = useMemo(() => {
    if (!input) return ['', null];
    if (mode === 'encode') return [b64Encode(input), null];
    const r = b64Decode(input);
    if (r === null) return ['', 'Not valid base64'];
    return [r, null];
  }, [input, mode]);

  const swap = () => {
    setMode(m => m === 'encode' ? 'decode' : 'encode');
    setInput(output);
  };

  return (
    <div className="enc-panel">
      <div className="enc-mode-pick">
        <button className={`enc-mode-btn ${mode === 'encode' ? 'is-active' : ''}`} onClick={() => setMode('encode')}>
          <Icon name="lock" />Encode
        </button>
        <button className={`enc-mode-btn ${mode === 'decode' ? 'is-active' : ''}`} onClick={() => setMode('decode')}>
          <Icon name="lock_open" />Decode
        </button>
        <div style={{ flex: 1 }} />
        <button className="lh-btn ghost" onClick={swap} disabled={!output}>
          <Icon name="swap_vert" />Swap & flip
        </button>
      </div>

      <IoPair
        inLabel={mode === 'encode' ? 'Plain text' : 'Base64 string'}
        outLabel={mode === 'encode' ? 'Base64 string' : 'Plain text'}
        input={input}
        setInput={setInput}
        output={output}
        error={error}
        sendToTitle={`Base64 ${mode === 'encode' ? 'encoded' : 'decoded'}`}
      />
    </div>
  );
}

// ============================================================
// URL panel
// ============================================================
function UrlPanel() {
  const [mode, setMode] = useState('encode');
  const [input, setInput] = useState('');
  const [whole, setWhole] = useState(false); // encodeURI vs encodeURIComponent
  const [output, error] = useMemo(() => {
    if (!input) return ['', null];
    try {
      if (mode === 'encode') {
        return [whole ? encodeURI(input) : encodeURIComponent(input), null];
      }
      return [whole ? decodeURI(input) : decodeURIComponent(input), null];
    } catch (e) {
      return ['', e.message];
    }
  }, [input, mode, whole]);

  const swap = () => {
    setMode(m => m === 'encode' ? 'decode' : 'encode');
    setInput(output);
  };

  return (
    <div className="enc-panel">
      <div className="enc-mode-pick">
        <button className={`enc-mode-btn ${mode === 'encode' ? 'is-active' : ''}`} onClick={() => setMode('encode')}>
          <Icon name="lock" />Encode
        </button>
        <button className={`enc-mode-btn ${mode === 'decode' ? 'is-active' : ''}`} onClick={() => setMode('decode')}>
          <Icon name="lock_open" />Decode
        </button>
        <div style={{ flex: 1 }} />
        <label className="enc-toggle">
          <input type="checkbox" checked={whole} onChange={e => setWhole(e.target.checked)} />
          <span>Whole URL (preserves <code>/</code>, <code>?</code>, <code>:</code>)</span>
        </label>
        <button className="lh-btn ghost" onClick={swap} disabled={!output}>
          <Icon name="swap_vert" />Swap & flip
        </button>
      </div>

      <IoPair
        inLabel={mode === 'encode' ? 'Raw text' : 'Encoded URL'}
        outLabel={mode === 'encode' ? 'Encoded URL' : 'Decoded text'}
        input={input}
        setInput={setInput}
        output={output}
        error={error}
        sendToTitle={`URL ${mode === 'encode' ? 'encoded' : 'decoded'}`}
        monoOutput
      />
    </div>
  );
}

// ============================================================
// Reusable input / output pair
// ============================================================
function IoPair({ inLabel, outLabel, input, setInput, output, error, sendToTitle, monoOutput }) {
  const [copied, setCopied] = useState(false);
  const copy = async () => {
    const ok = await copyText(output);
    if (ok) { setCopied(true); setTimeout(() => setCopied(false), 1500); }
  };
  return (
    <div className="enc-io-pair">
      <div className="enc-io-side">
        <div className="enc-io-head">
          <span>{inLabel}</span>
          <span className="enc-io-count">{input.length} chars</span>
          <div style={{ flex: 1 }} />
          {input && (
            <button className="lh-chip" onClick={() => setInput('')}>
              <Icon name="close" />Clear
            </button>
          )}
        </div>
        <textarea
          className="enc-input"
          placeholder="Paste or type here…"
          value={input}
          onChange={e => setInput(e.target.value)}
          spellCheck={false}
        />
      </div>
      <div className="enc-io-side">
        <div className="enc-io-head">
          <span>{outLabel}</span>
          <span className="enc-io-count">{output.length} chars</span>
          <div style={{ flex: 1 }} />
          {output && (
            <>
              <SendToButton payload={{ text: output, title: sendToTitle }} compact />
              <button className="lh-chip" onClick={copy}>
                <Icon name={copied ? 'check' : 'content_copy'} />
                {copied ? 'Copied' : 'Copy'}
              </button>
            </>
          )}
        </div>
        {error ? (
          <div className="enc-error inline">
            <Icon name="error" />
            <span>{error}</span>
          </div>
        ) : (
          <textarea
            className={`enc-input is-output ${monoOutput ? 'is-mono' : ''}`}
            value={output}
            readOnly
            spellCheck={false}
            placeholder="Output will appear here"
          />
        )}
      </div>
    </div>
  );
}

window.EncodeTool = EncodeTool;
