// ---- Domain Hunt (Pro tool) ----
const { useState: _hUseState, useRef: _hUseRef, useEffect: _hUseEffect } = React;
const _hTitle = (s) => (s && s.length ? s.charAt(0).toUpperCase() + s.slice(1) : s);
const _hMoney = (n) =>
  typeof n === 'number' && isFinite(n)
    ? '$' + Math.round(n).toLocaleString('en-US')
    : '—';

const HUNT_EXTS = ['.com', '.io', '.ai', '.co', '.net', '.org', '.app', '.dev', '.xyz'];
const HUNT_LENGTHS = [
  { id: 'any', label: 'Any length' },
  { id: 'short', label: 'Short · ≤5', min: 3, max: 5 },
  { id: 'medium', label: 'Medium · 6–9', min: 6, max: 9 },
  { id: 'long', label: 'Long · 10+', min: 10 },
];
const HUNT_WORDS = [
  { id: 'any', label: 'Any' },
  { id: 'one', label: 'One word' },
  { id: 'two', label: 'Two words' },
];

function HuntUpgrade({ onUpgrade }) {
  return (
    <div className="view">
      <h1 className="view-title">Domain Hunt</h1>
      <p className="view-sub">Find available names benchmarked against real top sales.</p>
      <div className="lock-card">
        <div className="lock-badge">Pro feature</div>
        <div className="lock-glyph" aria-hidden="true">⚿</div>
        <h2 className="lock-title">Hunt for undervalued domains</h2>
        <p className="lock-text">Domain Hunt studies recent record sales for the extension you choose, invents fresh brandable names in the same calibre, checks which are actually available, and estimates what each could be worth. Upgrade to Pro to start hunting.</p>
        <button className="btn-primary" onClick={onUpgrade}>Upgrade to Pro</button>
      </div>
    </div>
  );
}

// Benchmark icon — ascending bar chart
function BenchIcon() {
  return (
    <svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true" fill="currentColor">
      <rect x="0.5" y="8" width="3" height="5.5" rx="0.8"/>
      <rect x="5.5" y="4.5" width="3" height="9" rx="0.8"/>
      <rect x="10.5" y="0.5" width="3" height="13" rx="0.8"/>
    </svg>
  );
}

// Benchmark modal — comparable recorded sales for one domain
function HuntBenchmarkModal({ item, comps, onClose }) {
  _hUseEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);

  // Show the SAME estimated value the buy panel and value page show: the
  // canonical POST /api/domains/value figure, read cache-first so it is always
  // identical to what the user sees after clicking "Buy now".
  const fullDomain = (item.name + item.ext).toLowerCase();
  const [val, setVal] = _hUseState(() => {
    const cached = window.getValueCache && window.getValueCache(fullDomain);
    return cached ? window.mapValuation(cached) : null;
  });
  const [valState, setValState] = _hUseState(() => (val ? 'ok' : 'loading'));

  _hUseEffect(() => {
    let alive = true;
    const cached = window.getValueCache && window.getValueCache(fullDomain);
    if (cached) { setVal(window.mapValuation(cached)); setValState('ok'); return; }
    setValState('loading');
    fetch('/api/domains/value', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ domain: fullDomain }),
    })
      .then(async (resp) => {
        const data = await resp.json().catch(() => ({}));
        if (!alive) return;
        if (!resp.ok || typeof data.mid !== 'number') { setValState('error'); return; }
        if (window.setValueCache) window.setValueCache(fullDomain, data);
        setVal(window.mapValuation(data));
        setValState('ok');
      })
      .catch(() => { if (alive) setValState('error'); });
    return () => { alive = false; };
  }, [fullDomain]);

  const mid = val ? val.val : null;

  // Filter comps to matching extension when available, fall back to all.
  const extComps = comps.filter((c) => {
    const d = c.domain || '';
    return d.toLowerCase().endsWith(item.ext.toLowerCase());
  });
  const pool = extComps.length >= 5 ? extComps : comps;

  // Pick the comps NEAREST this domain's own estimate so every domain shows a
  // different, genuinely comparable set of sales — not the same global top
  // sales for every name. Before the estimate loads, fall back to top sales.
  const sorted = (mid && pool.length > 0
    ? [...pool].sort((a, b) => Math.abs(a.price - mid) - Math.abs(b.price - mid)).slice(0, 8)
    : [...pool].sort((a, b) => b.price - a.price).slice(0, 8)
  ).sort((a, b) => b.price - a.price);

  // Percentile: how many comps is this est. below?
  let percentileText = null;
  if (mid && pool.length > 0) {
    const below = pool.filter((c) => c.price <= mid).length;
    const pct = Math.round((below / pool.length) * 100);
    if (pct >= 75) percentileText = 'Top ' + (100 - pct) + '% of comparable sales';
    else if (pct >= 50) percentileText = 'Above median comparable sales';
    else if (pct >= 25) percentileText = 'Below median comparable sales';
    else percentileText = 'Entry-level for comparable sales';
  }

  return (
    <div className="hunt-bench-scrim" onClick={onClose} role="dialog" aria-modal="true">
      <div className="hunt-bench-modal" onClick={(e) => e.stopPropagation()}>
        <div className="hunt-bench-header">
          <span className="hunt-bench-domain">
            {_hTitle(item.name)}<span className="domain-ext">{item.ext}</span>
          </span>
          <button className="hunt-bench-close" onClick={onClose} aria-label="Close">×</button>
        </div>

        {valState === 'ok' && val ? (
          <div className="hunt-bench-est-section">
            <div className="hunt-bench-est-label">Estimated value</div>
            <div className="hunt-bench-est-val">{_hMoney(val.val)}</div>
            {(val.low || val.high) ? (
              <div className="hunt-bench-est-range">{_hMoney(val.low)} – {_hMoney(val.high)} range</div>
            ) : null}
            {percentileText ? <div className="hunt-bench-percentile">{percentileText}</div> : null}
          </div>
        ) : valState === 'loading' ? (
          <div className="hunt-bench-est-section">
            <div className="hunt-bench-est-label">Estimated value</div>
            <div className="hunt-bench-est-val hunt-bench-est-muted">Estimating…</div>
          </div>
        ) : (
          <div className="hunt-bench-est-section">
            <div className="hunt-bench-est-label">Estimated value</div>
            <div className="hunt-bench-est-val hunt-bench-est-muted">Unavailable right now</div>
          </div>
        )}

        {sorted.length > 0 ? (
          <React.Fragment>
            <div className="hunt-bench-comps-title">Comparable recorded sales</div>
            <div className="hunt-bench-list">
              {sorted.map((c, i) => (
                <div className="hunt-bench-item" key={i}>
                  <span className="hunt-bench-item-left">
                    <span className="hunt-bench-item-d">{c.domain}</span>
                    {c.venue ? <span className="hunt-bench-item-v">Sold at {c.venue}</span> : null}
                  </span>
                  <span className="hunt-bench-item-p">{_hMoney(c.price)}</span>
                </div>
              ))}
            </div>
          </React.Fragment>
        ) : null}

        <p className="hunt-bench-foot">Estimated values are AI guidance derived from comparable recorded sales — not appraisals or purchase offers.</p>
      </div>
    </div>
  );
}

// Single hunt result — matches the naming-page row layout
function HuntResultRow({ item, index, isFav, onFav, onBuy, comps }) {
  const [scoreOpen, setScoreOpen] = _hUseState(false);
  const [benchOpen, setBenchOpen] = _hUseState(false);
  const [popStyle, setPopStyle] = _hUseState(null);
  const chipRef = _hUseRef(null);

  const score = typeof item.score === 'number' ? item.score : null;
  const scoreCls = score == null ? '' : score >= 8 ? ' score-chip-hi' : score < 6 ? ' score-chip-lo' : '';

  // Position the score popover with fixed coordinates derived from the chip so
  // it escapes the results container's `overflow: hidden` and is never clipped.
  const toggleScore = () => {
    setScoreOpen((o) => {
      if (!o && chipRef.current) {
        const rect = chipRef.current.getBoundingClientRect();
        const narrow = window.innerWidth < 560;
        const roomBelow = window.innerHeight - rect.bottom;
        const up = roomBelow < 320 && rect.top > 320;
        const s = { position: 'fixed', zIndex: 250 };
        if (narrow) {
          s.left = '12px'; s.right = '12px'; s.width = 'auto';
        } else {
          s.width = '300px';
          s.right = Math.max(12, Math.round(window.innerWidth - rect.right)) + 'px';
        }
        if (up) { s.bottom = Math.round(window.innerHeight - rect.top + 8) + 'px'; s.top = 'auto'; }
        else { s.top = Math.round(rect.bottom + 8) + 'px'; s.bottom = 'auto'; }
        setPopStyle(s);
      }
      return !o;
    });
  };

  // Reuse the hunt's own AI judgement as the buy-panel "AI name review" so the
  // rating shown on the row and inside the buy panel are always identical.
  const review = score != null
    ? { score: score, verdict: item.verdict || '', benefits: Array.isArray(item.criteria) ? item.criteria : [] }
    : null;

  const domain = {
    id: item.name + item.ext,
    name: item.name,
    ext: item.ext,
    display: _hTitle(item.name) + item.ext,
    available: true,
    price: ((window.TLDS || []).find((x) => x.ext === item.ext) || {}).price || 12.99,
    currency: 'USD',
    review: review,
  };

  return (
    <React.Fragment>
      <div className={'row-block' + (scoreOpen ? ' row-block-pop' : '')} style={{ animationDelay: (index * 45) + 'ms' }}>
        <div className="row">
          <div className="row-main">
            <span className="domain-name">
              {_hTitle(item.name)}<span className="domain-ext">{item.ext}</span>
            </span>
            <span className="badge-available">
              <span className="dot"></span>Available
            </span>
          </div>
          <div className="row-side">
            {score != null ? (
              <div className="score-wrap">
                <button
                  ref={chipRef}
                  className={'score-chip' + scoreCls + (scoreOpen ? ' score-chip-on' : '')}
                  onClick={toggleScore}
                  title="AI brandability rating — click for details"
                  aria-expanded={scoreOpen}>
                  <span className="score-spark" aria-hidden="true">✦</span>{score.toFixed(1)}
                </button>
                {scoreOpen && window.ReactDOM && window.ReactDOM.createPortal
                  ? window.ReactDOM.createPortal(
                    <React.Fragment>
                      <div className="score-pop-scrim" style={{ zIndex: 249 }} onClick={() => setScoreOpen(false)}></div>
                      <div className="score-pop" style={popStyle || undefined}>
                        {window.NameReview
                          ? React.createElement(window.NameReview, { domain: domain, defaultOpen: true, compact: true })
                          : null}
                      </div>
                    </React.Fragment>,
                    document.body
                  )
                  : null}
              </div>
            ) : null}
            <button
              className={'fav-btn' + (isFav ? ' fav-on' : '')}
              onClick={() => onFav(domain)}
              title={isFav ? 'Remove from favorites' : 'Add to favorites'}
              aria-pressed={isFav}>
              {isFav ? '♥' : '♡'}
            </button>
            {comps && comps.length ? (
              <button
                className={'hunt-bench-btn' + (benchOpen ? ' hunt-bench-btn-on' : '')}
                onClick={() => setBenchOpen(true)}
                title="View market benchmark for this domain"
                aria-label="Market benchmark">
                <BenchIcon />
              </button>
            ) : null}
            <button className="btn-buy" onClick={() => onBuy(domain)}>Buy now</button>
          </div>
        </div>
      </div>
      {benchOpen ? (
        <HuntBenchmarkModal item={item} comps={comps || []} onClose={() => setBenchOpen(false)} />
      ) : null}
    </React.Fragment>
  );
}

function HuntView({ hasIdentity, onUpgrade, huntCost = 500, canAfford = true, onReserve, onCharged, onBuy, favIds, onFav, onRecord }) {
  const [ext, setExt] = _hUseState('any');
  const [extExpanded, setExtExpanded] = _hUseState(false);
  const [lenId, setLenId] = _hUseState('any');
  const [wordsId, setWordsId] = _hUseState('any');
  const [dashes, setDashes] = _hUseState(false);
  const [busy, setBusy] = _hUseState(false);
  const [err, setErr] = _hUseState(null);
  const [setupNeeded, setSetupNeeded] = _hUseState(false);
  const [res, setRes] = _hUseState(null); // { items, comps, checked }
  const inFlight = _hUseRef(false);

  if (!hasIdentity) return <HuntUpgrade onUpgrade={onUpgrade} />;

  // Every hunt aims to deliver a full page of HUNT_TARGET available names. The
  // server loops (generate → check availability) until it fills them or hits
  // its safety budget; we only charge when the full list comes back.
  const HUNT_TARGET = 10;
  const run = () => {
    if (busy || inFlight.current) return;
    if (!canAfford) { setErr('Not enough credits for a hunt.'); return; }
    const preset = HUNT_LENGTHS.find((l) => l.id === lenId) || {};
    const body = {
      extension: ext,
      words: wordsId,
      dashes: dashes,
      count: HUNT_TARGET,
    };
    if (preset.min) body.minLen = preset.min;
    if (preset.max) body.maxLen = preset.max;

    inFlight.current = true;
    setBusy(true); setErr(null); setSetupNeeded(false); setRes(null);
    fetch('/api/domains/hunt', {
      method: 'POST',
      credentials: 'include',
      cache: 'no-store',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    })
      .then(async (resp) => {
        const data = await resp.json().catch(() => ({}));
        if (resp.status === 503 && data && data.error === 'no_sales_data') {
          setSetupNeeded(true);
          return;
        }
        if (resp.status === 401) { setErr('Please sign in to run a hunt.'); return; }
        if (resp.status === 403 && data && data.error === 'pro_required') {
          setErr('Domain Hunt is a Pro feature. Upgrade to unlock it.');
          return;
        }
        if (!resp.ok) {
          setErr((data && data.message) ? data.message : 'Could not run the hunt. Please try again.');
          return;
        }
        const items = Array.isArray(data.items) ? data.items : [];
        // Charge ONLY when the hunt delivers the full list of HUNT_TARGET
        // available names. A short run that can't fill all 10 (e.g. tight
        // filters like short .com, where nearly everything is already
        // registered) costs the user nothing — credits are reserved/consumed
        // solely on a complete result set.
        if (items.length >= HUNT_TARGET) {
          if (onReserve && !onReserve()) { setErr('Not enough credits for a hunt.'); return; }
          if (onCharged) onCharged(ext === 'any' ? 'any' : ext);
        }
        setRes({
          items: items,
          comps: Array.isArray(data.comps) ? data.comps : [],
          checked: data.checked || 0,
          citation: typeof data.citation === 'string' ? data.citation : null,
        });
        // Surface this hunt's available names in History (live + persisted).
        // Record the names in History either way, but only attribute the
        // credit cost when the full list was delivered (and therefore charged).
        if (items.length && onRecord) onRecord(items, { credits: items.length >= HUNT_TARGET ? huntCost : 0 });
      })
      .catch(() => setErr('Could not reach the hunt service. Please try again.'))
      .then(() => { inFlight.current = false; setBusy(false); });
  };

  const favSet = new Set(favIds || []);

  return (
    <div className="view view-wide">
      <ToolHead title="Domain Hunt" sub="Find available names benchmarked against real record sales." />

      <div className="tool-card">
        <div className="hunt-field">
          <div className="hunt-field-label">Extension</div>
          {(() => {
            const allExts = (window.TLDS && window.TLDS.length) ? window.TLDS.map((t) => t.ext) : HUNT_EXTS;
            const VISIBLE = HUNT_EXTS.length;
            const shown = extExpanded ? allExts : allExts.slice(0, VISIBLE);
            const hiddenSelected = !extExpanded && ext !== 'any' && !shown.includes(ext);
            return (
              <div className="chips" role="group" aria-label="Extension">
                <button className={'chip' + (ext === 'any' ? ' chip-on' : '')} onClick={() => setExt('any')}>Any</button>
                {shown.map((e) => (
                  <button key={e} className={'chip' + (ext === e ? ' chip-on' : '')} onClick={() => setExt(e)}>{e}</button>
                ))}
                {hiddenSelected ? (
                  <button className="chip chip-on" onClick={() => setExt(ext)}>{ext}</button>
                ) : null}
                {allExts.length > VISIBLE ? (
                  <button className="chip chip-more" onClick={() => setExtExpanded(!extExpanded)}>
                    {extExpanded ? 'Show less' : '+' + (allExts.length - VISIBLE) + ' more'}
                  </button>
                ) : null}
              </div>
            );
          })()}
        </div>

        <div className="hunt-field">
          <div className="hunt-field-label">Letters</div>
          <div className="chips" role="group" aria-label="Letter count">
            {HUNT_LENGTHS.map((l) => (
              <button key={l.id} className={'chip' + (lenId === l.id ? ' chip-on' : '')} onClick={() => setLenId(l.id)}>{l.label}</button>
            ))}
          </div>
        </div>

        <div className="hunt-field">
          <div className="hunt-field-label">Words</div>
          <div className="chips" role="group" aria-label="Word count">
            {HUNT_WORDS.map((w) => (
              <button key={w.id} className={'chip' + (wordsId === w.id ? ' chip-on' : '')} onClick={() => setWordsId(w.id)}>{w.label}</button>
            ))}
          </div>
        </div>

        <div className="hunt-field hunt-field-row">
          <label className="opt-toggle">
            <input type="checkbox" checked={dashes} onChange={(e) => setDashes(e.target.checked)} />
            <span>Allow hyphens</span>
          </label>
        </div>

        <div className="hunt-actions">
          <button className="btn-primary" onClick={run} disabled={busy || !canAfford}>
            {busy ? 'Hunting…' : 'Hunt'}
          </button>
          <span className="tool-cost"><span className="tool-cost-dot">◈</span> <b>{huntCost} credits</b> per hunt</span>
        </div>
        {!canAfford ? <div className="tool-err">Not enough credits — top up to hunt.</div> : null}
        {err ? <div className="tool-err">{err}</div> : null}
      </div>

      {setupNeeded ? (
        <div className="hunt-setup">
          <div className="hunt-setup-glyph" aria-hidden="true">◷</div>
          <h3 className="hunt-setup-title">Sales data not loaded yet</h3>
          <p className="hunt-setup-text">Domain Hunt benchmarks names against real recorded sales held in our own database, seeded from publicly-reported sales at <a href="https://www.dnjournal.com/domainsales.htm" target="_blank" rel="noopener noreferrer">DNJournal</a>. No sales data has been loaded yet — once it's added, hunts will show real comps. We never make figures up.</p>
        </div>
      ) : null}

      {busy ? <SkeletonRows count={10} /> : null}

      {!busy && res ? (
        res.items.length === 0 ? (
          <div className="gen-error" role="status">
            No available names found this run{res.checked ? ' (checked ' + res.checked + ')' : ''}. Try a different extension or loosen the filters, then hunt again.
          </div>
        ) : (
          <React.Fragment>
            <div className="results-meta">
              <span>{res.items.length} available name{res.items.length > 1 ? 's' : ''}{res.checked ? ' · checked ' + res.checked : ''}{res.items.length < HUNT_TARGET ? ' · couldn’t fill all 10 — no credits charged' : ''}</span>
              {res.citation ? (
                <span className="results-cite">Benchmarked against real sales · <a href={res.citation} target="_blank" rel="noopener noreferrer">DNJournal</a></span>
              ) : null}
            </div>
            <div className="results">
              {res.items.map((it, idx) => (
                <HuntResultRow
                  key={it.name + it.ext}
                  item={it}
                  index={idx}
                  isFav={favSet.has(it.name + it.ext)}
                  onFav={onFav || (() => {})}
                  onBuy={onBuy}
                  comps={res.comps}
                />
              ))}
            </div>
          </React.Fragment>
        )
      ) : null}
    </div>
  );
}

Object.assign(window, { HuntView });
