/* Match & Wood — UTM Generator + Admin config views (React).
   Logic from window.MW_UTM. Loaded before app.jsx; exports to window. */
const { useState: useStateU, useEffect: useEffectU } = React;
const U = window.MW_UTM;
const LK = window.MW_LOOKUPS;

/* ---- small shared bits ---- */
function macroFor(platform) { return U.PLATFORM_MACROS[platform] || []; }

/* ===================================================================== */
/* UTM GENERATOR                                                         */
/* ===================================================================== */
function UtmView({ clients, copyText, onToast }) {
  const firstReal = (clients.find((c) => !c.base) || clients[0] || {}).client_code;
  const [clientCode, setClientCode] = useStateU(firstReal);
  const [platform, setPlatform] = useStateU('meta');
  const [base, setBase] = useStateU('https://renault.com.au/koleos');
  const [medium, setMedium] = useStateU('social_paid');
  const [source, setSource] = useStateU('meta');
  const [campaign, setCampaign] = useStateU('{{campaign.name}}');
  const [content, setContent] = useStateU('{{ad.name}}');
  const [term, setTerm] = useStateU('');
  const [utmid, setUtmid] = useStateU('');

  const clientObj = clients.find((c) => c.client_code === clientCode) || clients[0];
  const cfg = U.resolve(clientObj);
  const mediums = Object.keys(cfg.channel_mapping);
  const sources = cfg.channel_mapping[medium] || [];

  // keep medium / source valid as the client (and so the mapping) changes
  useEffectU(() => {
    if (mediums.indexOf(medium) === -1) {
      setMedium(mediums.indexOf('social_paid') !== -1 ? 'social_paid' : mediums[0]);
    }
  }, [clientCode]);
  useEffectU(() => {
    const ss = cfg.channel_mapping[medium] || [];
    if (ss.indexOf(source) === -1) setSource(ss[0] || '');
  }, [clientCode, medium]);

  const raw = { source, medium, campaign, content, term, utmid };
  const params = U.buildParams(raw);
  const segs = U.urlSegments(base, params);
  const report = U.validate(cfg, params, base, platform);
  const all = report.L1.concat(report.L2);
  const overall = U.worst(all);
  const counts = all.reduce((a, c) => { a[c.s] = (a[c.s] || 0) + 1; return a; }, {});
  const labelMap = { pass: 'Pass', fail: 'Fail', warning: 'Needs review' };

  function insertMacro(field, m) {
    if (field === 'campaign') setCampaign(m); else setContent(m);
    if (platform === 'static') setPlatform(U.platformOfMacro(m));
  }
  function doCopy(encode, msg) {
    const txt = U.buildUrl(base, params, encode);
    if (!txt) { onToast('Nothing to copy'); return; }
    copyText(txt); onToast(msg);
  }
  function reset() { setBase(''); setCampaign(''); setContent(''); setTerm(''); setUtmid(''); }

  const macroChips = (field) => {
    const list = macroFor(platform);
    if (platform === 'static' || list.length === 0) {
      return <div className="macros"><span className="macro-none">Static values — no macros for this platform context.</span></div>;
    }
    return (
      <div className="macros">
        {list.map((m) => (
          <button key={m} className="macro-chip" onClick={() => insertMacro(field, m)}>{m}</button>
        ))}
      </div>
    );
  };

  return (
    <div className="wrap">
      <main>
        <div className="intro">
          <h1>Build a tracked campaign URL</h1>
          <p>Pick the client and platform — the source list, campaign-code rule and macro
             set follow the client&rsquo;s convention. Every parameter is validated live against
             the same rules the <span style={{ fontStyle: 'italic' }}>utm-qa</span> checker uses.</p>
        </div>

        <div className="utm-form">
          <div className="utm-block">
            <div className="step-head">
              <span className="step-num">01</span>
              <span className="step-title">Context</span>
              <span className="step-hint">Client &amp; platform set the rules</span>
            </div>
            <div className="utm-grid">
              <div className="field">
                <span className="field-label">Client</span>
                <select className="sel" value={clientCode} onChange={(e) => setClientCode(e.target.value)}>
                  {clients.map((c) => <option key={c.client_code} value={c.client_code}>{c.client_name}</option>)}
                </select>
              </div>
              <div className="field">
                <span className="field-label">Platform context</span>
                <select className="sel" value={platform} onChange={(e) => setPlatform(e.target.value)}>
                  {U.PLATFORMS.map((p) => <option key={p.id} value={p.id}>{p.label} — {p.blurb}</option>)}
                </select>
              </div>
              {clientObj.note && (
                <div className="client-note">
                  <span className="cn-label">{clientObj.client_name} · rules</span>
                  {clientObj.note}
                </div>
              )}
            </div>
          </div>

          <div className="utm-block">
            <div className="step-head">
              <span className="step-num">02</span>
              <span className="step-title">Parameters</span>
              <span className="step-hint">Locked lists keep sources on-convention</span>
            </div>
            <div className="utm-grid">
              <div className="field full">
                <span className="field-label">Landing page URL
                  <span className="locked">— required</span></span>
                <input className="inp" value={base} placeholder="https://renault.com.au/koleos"
                       onChange={(e) => setBase(e.target.value)} />
              </div>

              <div className="field">
                <span className="field-label">utm_medium <span className="locked">— channel</span></span>
                <select className="sel" value={medium} onChange={(e) => setMedium(e.target.value)}>
                  {mediums.map((m) => <option key={m} value={m}>{m}</option>)}
                </select>
              </div>
              <div className="field">
                <span className="field-label">utm_source</span>
                <select className={'sel' + (source ? '' : ' placeholder')} value={source} onChange={(e) => setSource(e.target.value)}>
                  {sources.length === 0 && <option value="">No sources mapped</option>}
                  {sources.map((s) => <option key={s} value={s}>{s}</option>)}
                </select>
                <span className="field-hint">{sources.length ? 'Allowed for ' + medium : 'No sources mapped for ' + medium}</span>
              </div>

              <div className="field full">
                <span className="field-label">utm_campaign <span className="locked">— required</span></span>
                <input className="inp" value={campaign} placeholder="MW012345 / SNZ293 / campaign name"
                       onChange={(e) => setCampaign(e.target.value)} />
                {macroChips('campaign')}
              </div>

              <div className="field full">
                <span className="field-label">utm_content <span className="locked">— required</span></span>
                <input className="inp" value={content} placeholder="ad / creative identifier"
                       onChange={(e) => setContent(e.target.value)} />
                {macroChips('content')}
              </div>

              <div className="field">
                <span className="field-label">utm_term <span className="locked">— optional</span></span>
                <input className="inp" value={term} onChange={(e) => setTerm(e.target.value)} />
              </div>
              <div className="field">
                <span className="field-label">utm_id <span className="locked">— optional</span></span>
                <input className="inp" value={utmid} onChange={(e) => setUtmid(e.target.value)} />
              </div>
            </div>
          </div>
        </div>

        <div className="utm-foot">
          <b>How it works.</b> Layer 1 checks static rules — required parameters, lowercase casing,
          the client&rsquo;s landing-page allow-list and campaign-code pattern. Layer 2 checks that any
          macros match the chosen platform context. Layer 3 (a live fetch for analytics tags) runs
          server-side and isn&rsquo;t part of this prototype.
        </div>
      </main>

      <aside className="preview">
        <div className="url-card">
          <div className="name-eyebrow">Generated URL</div>
          <div className="url-box">
            {base ? <span>{base}</span> : <span className="uph">(enter landing page URL)</span>}
            {segs.map((s, i) => (
              <React.Fragment key={i}>
                {s.sep}<span className="uk">{s.key}</span>=
                {s.macro ? <span className="um">{s.val}</span> : s.val}
              </React.Fragment>
            ))}
          </div>
          <div className="url-actions">
            <button className="btn-copy" onClick={() => doCopy(false, 'URL copied')}>Copy URL</button>
            <button className="url-ghost" onClick={() => doCopy(true, 'Encoded URL copied')}>Copy encoded</button>
            <button className="url-ghost" onClick={reset}>Reset</button>
          </div>
        </div>

        <div className="valid-card">
          <div className="name-eyebrow">Validation</div>
          <div className="valid-head">
            <span className={'status-pill ' + overall}><span className="dot"></span>{labelMap[overall]}</span>
            <span className="valid-counts">{counts.pass || 0} pass · {counts.fail || 0} fail · {counts.warning || 0} review</span>
          </div>
          <CheckBlock title="Layer 1 · Static" checks={report.L1} />
          <CheckBlock title="Layer 2 · Macros" checks={report.L2} />
        </div>
      </aside>
    </div>
  );
}

function CheckBlock({ title, checks }) {
  return (
    <React.Fragment>
      <div className="layer-title">{title}</div>
      {checks.map((c, i) => {
        const ic = c.s === 'pass' ? '✓' : c.s === 'fail' ? '✕' : '!';
        return (
          <div className={'check ' + c.s} key={i}>
            <span className="ic">{ic}</span>
            <span className="ctext">
              <span className="ct">{c.t}</span>
              {c.d && <span className="cd">{c.d}</span>}
            </span>
          </div>
        );
      })}
    </React.Fragment>
  );
}

/* ===================================================================== */
/* ADMIN — client config                                                 */
/* ===================================================================== */
function ChipEditor({ values, onChange, placeholder, mono }) {
  const [draft, setDraft] = useStateU('');
  function commit() {
    const v = draft.trim();
    if (v && values.indexOf(v) === -1) onChange(values.concat([v]));
    setDraft('');
  }
  return (
    <div className={'chip-edit' + (mono ? ' ed-mono' : '')}>
      {values.map((v, i) => (
        <span className="chip" key={v + i}>{v}
          <button className="chip-x" title="Remove" onClick={() => onChange(values.filter((_, j) => j !== i))}>×</button>
        </span>
      ))}
      <input className="chip-input" value={draft} placeholder={placeholder || 'Add…'}
             onChange={(e) => setDraft(e.target.value)}
             onKeyDown={(e) => {
               if (e.key === 'Enter' || e.key === ',') { e.preventDefault(); commit(); }
               else if (e.key === 'Backspace' && !draft && values.length) onChange(values.slice(0, -1));
             }}
             onBlur={commit} />
    </div>
  );
}

const ADMIN_PLATFORMS = ['meta', 'cm360', 'dv360', 'google-ads', 'ttd'];

function AdminView({ clients, setClients, onToast }) {
  const [sel, setSel] = useStateU((clients[0] || {}).client_code);
  const client = clients.find((c) => c.client_code === sel) || clients[0];
  const cfg = U.resolve(client);

  function patch(p) {
    setClients(clients.map((c) => c.client_code === sel ? Object.assign({}, c, p) : c));
  }
  function addClient() {
    let n = 1, code;
    do { code = 'client_' + n; n++; } while (clients.some((c) => c.client_code === code));
    const fresh = { client_code: code, client_name: 'New client', note: '' };
    setClients(clients.concat([fresh]));
    setSel(code);
    onToast('Client added (session only)');
  }
  function delClient() {
    if (client.base) return;
    const rest = clients.filter((c) => c.client_code !== sel);
    setClients(rest);
    setSel((rest[0] || {}).client_code);
    onToast('Client removed (session only)');
  }

  // channel mapping helpers (operate on a working copy of the resolved mapping)
  const mapping = client.channel_mapping || U.DEFAULTS.channel_mapping;
  function setMappingRow(ch, arr) {
    patch({ channel_mapping: Object.assign({}, mapping, { [ch]: arr }) });
  }
  // aliases
  const aliases = client.utm_source_aliases || U.DEFAULTS.utm_source_aliases;
  const aliasRows = Object.keys(aliases).map((k) => [k, aliases[k]]);
  function setAliases(rows) {
    const obj = {};
    rows.forEach(([k, v]) => { if (k.trim()) obj[k.trim()] = v.trim(); });
    patch({ utm_source_aliases: obj });
  }
  // static source by platform
  const staticVals = (client.preferred_static_values && client.preferred_static_values.utm_source_by_platform) || {};
  function setStatic(plat, val) {
    const next = Object.assign({}, staticVals);
    if (val.trim()) next[plat] = val.trim(); else delete next[plat];
    patch({ preferred_static_values: { utm_source_by_platform: next } });
  }
  // preferred macros by platform
  const prefMacros = client.preferred_macros_by_platform || {};
  function setMacro(plat, key, val) {
    const platObj = Object.assign({}, prefMacros[plat] || {});
    if (val.trim()) platObj[key] = val.trim(); else delete platObj[key];
    const next = Object.assign({}, prefMacros, { [plat]: platObj });
    if (Object.keys(platObj).length === 0) delete next[plat];
    patch({ preferred_macros_by_platform: next });
  }

  return (
    <div className="admin-wrap">
      <div className="admin-intro">
        <h1>UTM client templates</h1>
        <p>Configure the rules each client&rsquo;s tracked URLs are built and validated against —
           campaign-code pattern, landing-page allow-list, channel-to-source mapping, source aliases
           and platform defaults. Clients defined here populate the UTM generator&rsquo;s dropdown.</p>
        <span className="mockup-flag">Prototype — edits drive the generator this session but are not saved on reload.</span>
      </div>

      <div className="lookup-band">
        <div className="ed-head">
          <h3>Naming lookup tables</h3>
          <span className="ed-sub">Code ↔ name maps the dashboards decode against</span>
        </div>
        <p className="lookup-copy">
          Locked fields in a campaign name render as short codes (e.g. <code>SCH</code>, <code>CNV</code>,
          <code> CON</code>). These tables map every code back to its full name — plus geo country/state
          codes and the per-platform field order — so the dashboards can show readable names and we keep
          one cross-client source of truth. Export and hand to the BI/dashboard team.
        </p>
        <div className="lookup-actions">
          <button className="btn-ghost" onClick={() => { LK.download('csv'); onToast('Lookup tables (CSV) downloaded'); }}>Download CSV</button>
          <button className="btn-ghost" onClick={() => { LK.download('json'); onToast('Lookup tables (JSON) downloaded'); }}>Download JSON</button>
        </div>
      </div>

      <div className="client-list">
        <div className="cl-head">
          <h2>Clients</h2>
          <button className="cl-add" onClick={addClient}>+ Add</button>
        </div>
        {clients.map((c) => (
          <button key={c.client_code} className="cl-item" aria-pressed={c.client_code === sel}
                  onClick={() => setSel(c.client_code)}>
            <span className="cl-name">{c.client_name}</span>
            <span className="cl-code">{c.client_code}</span>
            {c.base && <span className="cl-base-tag">Base defaults</span>}
          </button>
        ))}
      </div>

      <div className="editor">
        {/* Identity */}
        <div className="ed-section">
          <div className="ed-head"><h3>Identity</h3>
            {client.base && <span className="ed-sub">Inherited by every client</span>}</div>
          <div className="ed-grid">
            <div className="ed-field">
              <span className="ed-label">Client name</span>
              <input className="inp" value={client.client_name || ''} onChange={(e) => patch({ client_name: e.target.value })} />
            </div>
            <div className="ed-field">
              <span className="ed-label">Client code</span>
              <input className="inp ed-mono" value={client.client_code || ''} disabled={client.base}
                     onChange={(e) => {
                       const code = e.target.value.trim();
                       setClients(clients.map((c) => c.client_code === sel ? Object.assign({}, c, { client_code: code }) : c));
                       setSel(code);
                     }} />
              {client.base && <span className="ed-hint">The base record can&rsquo;t be renamed.</span>}
            </div>
          </div>
        </div>

        {/* Campaign code */}
        <div className="ed-section">
          <div className="ed-head"><h3>Campaign code</h3>
            <span className="ed-sub">Regex — what a valid code looks like</span></div>
          <div className="ed-grid">
            <div className="ed-field">
              <span className="ed-label">Full code pattern</span>
              <input className="inp ed-mono" value={cfg.mw_campaign_code_pattern}
                     onChange={(e) => patch({ mw_campaign_code_pattern: e.target.value })} />
              <span className="ed-hint">e.g. ^MW\d&#123;6&#125;$ (Renault) · ^SNZ\d&#123;3&#125;$ (Snooze)</span>
            </div>
            <div className="ed-field">
              <span className="ed-label">Pattern inside utm_campaign</span>
              <input className="inp ed-mono" value={cfg.mw_campaign_code_in_utm_pattern}
                     onChange={(e) => patch({ mw_campaign_code_in_utm_pattern: e.target.value })} />
              <span className="ed-hint">Looser, case-insensitive match used in validation.</span>
            </div>
          </div>
        </div>

        {/* Landing domains */}
        <div className="ed-section">
          <div className="ed-head"><h3>Landing-page allow-list</h3>
            <span className="ed-sub">Blank = any domain allowed</span></div>
          <div className="ed-field full">
            <ChipEditor values={client.landing_page_domains_allowed || []}
                        onChange={(v) => patch({ landing_page_domains_allowed: v })}
                        placeholder="renault.com.au  — type and press Enter" mono />
            <span className="ed-hint">URLs whose host isn&rsquo;t on this list fail validation. Leave empty for clients with no domain restriction.</span>
          </div>
        </div>

        {/* Channel mapping */}
        <div className="ed-section">
          <div className="ed-head"><h3>Channel → source mapping</h3>
            <span className="ed-sub">Allowed utm_source values per utm_medium</span></div>
          <div>
            {Object.keys(mapping).map((ch) => (
              <div className="map-row" key={ch}>
                <span className="map-key">{ch}</span>
                <ChipEditor values={mapping[ch]} onChange={(v) => setMappingRow(ch, v)}
                            placeholder="add source…" mono />
              </div>
            ))}
          </div>
        </div>

        {/* Source aliases */}
        <div className="ed-section">
          <div className="ed-head"><h3>Source aliases</h3>
            <span className="ed-sub">Flagged in validation, mapped to canonical</span></div>
          <div className="ed-grid">
            <div className="ed-field full" style={{ gap: '12px' }}>
              {aliasRows.map((row, i) => (
                <div className="alias-row" key={i}>
                  <input className="inp ed-mono" value={row[0]} placeholder="alias"
                         onChange={(e) => { const r = aliasRows.slice(); r[i] = [e.target.value, row[1]]; setAliases(r); }} />
                  <span className="alias-arrow">→</span>
                  <input className="inp ed-mono" value={row[1]} placeholder="canonical"
                         onChange={(e) => { const r = aliasRows.slice(); r[i] = [row[0], e.target.value]; setAliases(r); }} />
                  <button className="alias-del" title="Remove"
                          onClick={() => setAliases(aliasRows.filter((_, j) => j !== i))}>×</button>
                </div>
              ))}
              <button className="alias-add" onClick={() => setAliases(aliasRows.concat([['', '']]))}>+ Add alias</button>
            </div>
          </div>
        </div>

        {/* Platform defaults */}
        <div className="ed-section">
          <div className="ed-head"><h3>Static source values</h3>
            <span className="ed-sub">For clients using static values, not macros</span></div>
          <div className="plat-table">
            <div className="plat-head" style={{ gridTemplateColumns: '140px 1fr' }}>
              <span>Platform</span><span>utm_source value</span>
            </div>
            {ADMIN_PLATFORMS.map((plat) => (
              <div className="plat-row" key={plat} style={{ gridTemplateColumns: '140px 1fr' }}>
                <span className="plat-name">{plat}</span>
                <input className="inp ed-mono" value={staticVals[plat] || ''} placeholder="—"
                       onChange={(e) => setStatic(plat, e.target.value)} />
              </div>
            ))}
          </div>
        </div>

        <div className="ed-section">
          <div className="ed-head"><h3>Preferred macros</h3>
            <span className="ed-sub">Suggested dynamic values per platform</span></div>
          <div className="plat-table">
            <div className="plat-head"><span>Platform</span><span>utm_campaign</span><span>utm_content</span></div>
            {ADMIN_PLATFORMS.map((plat) => (
              <div className="plat-row" key={plat}>
                <span className="plat-name">{plat}</span>
                <input className="inp ed-mono" value={(prefMacros[plat] && prefMacros[plat].utm_campaign) || ''} placeholder="—"
                       onChange={(e) => setMacro(plat, 'utm_campaign', e.target.value)} />
                <input className="inp ed-mono" value={(prefMacros[plat] && prefMacros[plat].utm_content) || ''} placeholder="—"
                       onChange={(e) => setMacro(plat, 'utm_content', e.target.value)} />
              </div>
            ))}
          </div>
        </div>

        {/* Note */}
        <div className="ed-section">
          <div className="ed-head"><h3>Client note</h3>
            <span className="ed-sub">Shown to users in the generator</span></div>
          <textarea className="bulk-area" value={client.note || ''}
                    placeholder="Conventions, known issues, anything a planner should know…"
                    onChange={(e) => patch({ note: e.target.value })} />
        </div>

        {/* Danger */}
        <div className="ed-danger">
          <span className="dg-text">{client.base
            ? 'The base defaults record is required and can&rsquo;t be deleted.'
            : 'Remove this client from the roster for this session.'}</span>
          <button className="btn-danger" disabled={client.base} onClick={delClient}>Delete client</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { UtmView, AdminView });
