const { useState: useARPState, useEffect: useARPEffect, useRef: useARPRef } = React;

function _arStatusText(stage) {
  if (!stage) return 'Starting auto-remodel...';
  switch (stage) {
    case 'queued': return 'Starting auto-remodel...';
    case 'crawling': return 'Crawling and scoring...';
    case 'picked': return 'Top picks selected...';
    case 'filtering': return 'Filtering picked ads...';
    case 'filter_done': return 'Filter audit complete...';
    case 'remodeling': return 'Generating remodeled scripts...';
    case 'done': return 'Auto-remodel complete';
    case 'cancelled': return 'Auto-remodel stopped';
    case 'failed': return 'Auto-remodel failed';
    default: return stage;
  }
}

function _sumProgressValue(ev, key) {
  const progress = ev?.platform_progress || {};
  const counts = ev?.platform_counts || {};
  return Object.keys({ ...progress, ...counts }).reduce((total, platform) => {
    const progressValue = Number(progress[platform]?.[key] || 0);
    const countValue = Number(counts[platform]?.[key] || 0);
    return total + Math.max(progressValue, countValue);
  }, 0);
}

function _sumFetched(ev) {
  if (typeof ev?.ads_fetched_total === 'number') return ev.ads_fetched_total;
  const fetched = ev?.platform_ads_fetched || {};
  const progressChecked = _sumProgressValue(ev, 'ads_checked');
  const fetchedTotal = Object.values(fetched).reduce((total, value) => total + Number(value || 0), 0);
  return Math.max(progressChecked, fetchedTotal);
}

function _arProgressMetrics(stage, adsFound, targetAds, picked, varsDone, varsTotal, ev) {
  const checked = _sumFetched(ev);
  const scored = Math.max(
    Number(ev?.total_ads_scored || 0),
    _sumProgressValue(ev, 'scored'),
  );
  const pickedCount = Math.max(
    Number(picked || 0),
    Number(ev?.picked_count || ev?.picked || 0),
    Array.isArray(ev?.picked_ad_ids) ? ev.picked_ad_ids.length : 0,
  );
  const foundCount = Math.max(Number(adsFound || 0), pickedCount);
  const target = Math.max(Number(targetAds || 0), Number(ev?.target_ads || 0), foundCount);
  const remodelDone = Math.max(
    Number(varsDone || 0),
    Number(ev?.completed || 0) + Number(ev?.failed || 0),
    _sumProgressValue(ev, 'remodel_done') + _sumProgressValue(ev, 'remodel_failed'),
  );
  const remodelTotal = Math.max(Number(varsTotal || 0), Number(ev?.jobs_started || ev?.jobs_created || 0), remodelDone);
  const directionsDone = Number(ev?.directions_done || 0);
  const directionsTotal = Number(ev?.directions_total || 0);

  let pct = 0;
  if (stage === 'done') {
    pct = 100;
  } else if (stage === 'failed') {
    pct = 8;
  } else {
    const crawlRatio = directionsTotal > 0
      ? Math.min(directionsDone / directionsTotal, 1)
      : (checked > 0 ? 0.5 : 0);
    const scoreRatio = checked > 0 ? Math.min(scored / Math.max(checked, 1), 1) : 0;
    const pickRatio = target > 0 ? Math.min(foundCount / target, 1) : 0;
    const remodelRatio = remodelTotal > 0 ? Math.min(remodelDone / remodelTotal, 1) : 0;
    pct = 8 + (crawlRatio * 22) + (scoreRatio * 20) + (pickRatio * 25) + (remodelRatio * 25);
    if (stage === 'cancelled') pct = Math.max(8, pct);
  }

  return {
    checked,
    scored,
    pickedCount,
    target,
    remodelDone,
    remodelTotal,
    pct: Math.max(0, Math.min(100, pct)),
  };
}

function _arMetaText(stage, adsFound, targetAds, picked, varsDone, varsTotal, ev) {
  if (stage === 'failed' && ev?.error) return ev.error;
  const metrics = _arProgressMetrics(stage, adsFound, targetAds, picked, varsDone, varsTotal, ev);
  const bits = [];
  const directionProgress = Object.values(ev?.direction_progress || {}).filter(Boolean);
  const coverageTotal = Number(ev?.coverage_total || 0) || directionProgress.length;
  const coverageTouched = Number(ev?.coverage_touched || 0) || directionProgress.filter(row => row.touched).length;
  if (coverageTotal) bits.push(`${coverageTouched}/${coverageTotal} searches touched`);
  bits.push(`${metrics.checked} crawled`);
  bits.push(`${metrics.scored} scored`);
  const pickTarget = metrics.target || targetAds || 0;
  bits.push(pickTarget > 0 ? `${metrics.pickedCount}/${pickTarget} picked` : `${metrics.pickedCount} picked`);
  if (metrics.remodelTotal > 0) bits.push(`${metrics.remodelDone}/${metrics.remodelTotal} remodels done`);
  if (ev?.overrides) bits.push(`${ev.overrides} filter override${ev.overrides === 1 ? '' : 's'}`);
  return bits.join(' · ');
}

function _directionStatusText(row) {
  const raw = row?.message || row?.last_message || row?.stop_reason || row?.status || '';
  const text = String(raw).replace(/_/g, ' ').trim();
  if (!text || text === 'running') return row?.touched ? 'touched' : 'pending';
  if (text === 'target met') return 'run target reached';
  return text;
}

function _directionProgressGroups(ev) {
  const rows = Object.values(ev?.direction_progress || {})
    .filter(Boolean)
    .sort((a, b) => {
      const left = `${a.direction_name || a.direction_id || ''}:${a.source || ''}`;
      const right = `${b.direction_name || b.direction_id || ''}:${b.source || ''}`;
      return left.localeCompare(right);
    });
  const groups = rows.reduce((acc, row) => {
    const key = row.direction_id || row.direction_name || 'unknown';
    if (!acc[key]) {
      acc[key] = {
        key,
        name: row.direction_name || row.direction_id || 'Unknown direction',
        rows: [],
      };
    }
    acc[key].rows.push(row);
    return acc;
  }, {});
  return Object.values(groups);
}

function _formatDirectionProgressRow(row) {
  const label = (PLATFORMS[row.source]?.label || row.source || 'source').toUpperCase();
  const ads = Number(row.ads_checked || 0);
  const pages = Number(row.pages_fetched || row.internal_pages_fetched || 0);
  const scored = Number(row.scored || 0);
  const winners = Number(row.winners || 0);
  const picked = Number(row.picked || 0);
  return `${label}: ${ads} ads fetched · ${pages} page${pages === 1 ? '' : 's'} · ${scored} scored · ${winners} winners · ${picked} picked · ${_directionStatusText(row)}`;
}

function _platformProgressRows(ev, sources = {}) {
  const fetched = ev?.platform_ads_fetched || {};
  const counts = ev?.platform_counts || {};
  const progress = ev?.platform_progress || {};
  const selected = Object.keys(sources || {}).filter(key => sources[key]);
  const platforms = [...new Set([...selected, ...Object.keys(fetched), ...Object.keys(counts), ...Object.keys(progress)])];
  if (!platforms.length) return [];
  return platforms
    .sort()
    .map((platform) => {
      const entry = progress[platform] || {};
      const scored = Number(entry.scored ?? counts[platform]?.scored ?? 0);
      const winners = Number(entry.winners ?? counts[platform]?.winners ?? 0);
      const checked = Number(entry.ads_checked ?? fetched[platform] ?? 0);
      const picked = Number(entry.picked || 0);
      const skippedLow = Number(entry.skipped_low_score || 0);
      const skippedNoInput = Number(entry.skipped_no_input || 0);
      const duplicates = Number(entry.duplicates_hidden || 0);
      const remodelDone = Number(entry.remodel_done || 0);
      const remodelStarted = Number(entry.remodel_started || 0);
      const remodelFailed = Number(entry.remodel_failed || 0);
      const remodelReused = Number(entry.remodel_reused || 0);
      const threshold = Number(entry.score_threshold || 0);
      const label = (PLATFORMS[platform]?.label || platform).toUpperCase();
      const bits = [
        `${label}: ${checked} ads checked`,
        `${scored} scored`,
        `${winners} winners`,
        `${picked} picked`,
      ];
      if (skippedLow) bits.push(`${skippedLow} skipped low score${threshold ? ` < ${threshold}` : ''}`);
      if (skippedNoInput) bits.push(`${skippedNoInput} skipped no input`);
      if (duplicates) bits.push(`${duplicates} duplicates hidden`);
      if (remodelStarted || remodelDone || remodelFailed || remodelReused) {
        bits.push(`${remodelDone}/${remodelStarted || remodelDone} remodels done`);
      }
      if (remodelFailed) bits.push(`${remodelFailed} remodel failed`);
      if (remodelReused) bits.push(`${remodelReused} reused`);
      return { platform, text: bits.join(' · ') };
    });
}

window.AutoRemodelPanel = function AutoRemodelPanel({
  open,
  onClose,
  directionOptions = [],
  running,
  stage,
  lastEvent,
  adsFound = 0,
  targetAds = 0,
  variantsDone = 0,
  variantsTotal = 0,
  sources = { foreplay: true, adspy: true, brandsearch: true },
  onToggleSource,
  onSelectAllSources,
  onRun,
  onStop,
  onRetryFailed,
  starting = false,
  strategy = '',
  onStrategyChange,
}) {
  const [count, setCount] = useARPState('5');
  const [maxAdsPerDirection, setMaxAdsPerDirection] = useARPState('');
  const [maxAdsPerPlatform, setMaxAdsPerPlatform] = useARPState('');
  const [selectedDirectionIds, setSelectedDirectionIds] = useARPState(new Set());
  const [pickerOpen, setPickerOpen] = useARPState(false);
  const [estimate, setEstimate] = useARPState(null);
  const [estimating, setEstimating] = useARPState(false);
  const [estimateError, setEstimateError] = useARPState('');
  const [estimateDirty, setEstimateDirty] = useARPState(false);
  const pickerRef = useARPRef(null);
  const defaultDirectionsLoadedRef = useARPRef(false);
  const directions = Array.isArray(directionOptions) ? directionOptions : [];
  const selectedIds = [...selectedDirectionIds];
  const countMax = window.RESILIA_LIMITS?.autoRemodelCountMax || 10000;
  const adsPerDirectionMax = window.RESILIA_LIMITS?.searchAdsPerDirectionMax || 10000;
  const adsPerPlatformMax = window.RESILIA_LIMITS?.searchAdsPerPlatformMax || 100000;
  const capNum = Math.max(1, Math.min(countMax, parseInt(count, 10) || 5));
  const variants = 1;
  const directionBudget = maxAdsPerDirection === ''
    ? null
    : Math.max(1, Math.min(adsPerDirectionMax, parseInt(maxAdsPerDirection, 10) || 1));
  const platformBudget = maxAdsPerPlatform === ''
    ? null
    : Math.max(1, Math.min(adsPerPlatformMax, parseInt(maxAdsPerPlatform, 10) || 1));
  const randomPoolSize = directions.length;
  const pickerLabel = selectedIds.length
    ? `${selectedIds.length} direction${selectedIds.length === 1 ? '' : 's'} selected`
    : `Random ${Math.min(capNum, randomPoolSize)} direction${Math.min(capNum, randomPoolSize) === 1 ? '' : 's'}`;
  const labelFor = (d) => d.display_name || d.brand_name || d.name || d.id;
  const typeLabel = (d) => d.type === 'competitor' ? 'Competitor' : 'Keyword';
  const selectedDirectionPreview = selectedIds.length
    ? directions.filter(d => selectedDirectionIds.has(d.id))
    : [];
  const liveKeys = Object.keys(PLATFORMS).filter(k => k === 'foreplay' || k === 'adspy' || k === 'brandsearch');
  const selectedSources = liveKeys.filter(k => sources[k]);
  const busy = running || starting;

  useARPEffect(() => {
    if (running && targetAds > 0) setCount(String(targetAds));
  }, [running, targetAds]);

  useARPEffect(() => {
    if (!directions.length || defaultDirectionsLoadedRef.current) return;
    setSelectedDirectionIds(new Set(directions.map(d => d.id).filter(Boolean)));
    defaultDirectionsLoadedRef.current = true;
  }, [directions.map(d => d.id).join('|')]);

  useARPEffect(() => {
    if (!open || !estimateDirty) return;
    let cancelled = false;
    if (selectedSources.length === 0) {
      setEstimate(null);
      setEstimating(false);
      setEstimateError('Pick at least one source');
      return () => { cancelled = true; };
    }
    setEstimating(true);
    setEstimateError('');
    const timer = setTimeout(async () => {
      try {
        const out = await RESILIA_API.estimateAutoRemodel({
          mode: 'auto_search',
          directionId: null,
          directionIds: selectedIds,
          count: capNum,
          nVariants: variants,
          platforms: selectedSources,
        });
        if (!cancelled) setEstimate(out);
      } catch (e) {
        if (!cancelled) setEstimateError(e.message || 'Estimate unavailable');
      } finally {
        if (!cancelled) setEstimating(false);
      }
    }, 750);
    return () => { cancelled = true; clearTimeout(timer); };
  }, [open, estimateDirty, count, selectedIds.join('|'), selectedSources.join('|')]);

  useARPEffect(() => {
    if (!pickerOpen) return;
    const onClick = (e) => {
      if (pickerRef.current && !pickerRef.current.contains(e.target)) setPickerOpen(false);
    };
    const onKey = (e) => { if (e.key === 'Escape') setPickerOpen(false); };
    document.addEventListener('mousedown', onClick);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onClick);
      document.removeEventListener('keydown', onKey);
    };
  }, [pickerOpen]);

  if (!open && !running && stage !== 'done' && stage !== 'failed' && stage !== 'cancelled') return null;

  const pickedCount = lastEvent?.picked_count
    ?? (Array.isArray(lastEvent?.picked_ad_ids) ? lastEvent.picked_ad_ids.length : null)
    ?? lastEvent?.picked;
  const isComplete = stage === 'done';
  const progressMetrics = _arProgressMetrics(stage, adsFound, targetAds, pickedCount, variantsDone, variantsTotal, lastEvent);
  const pct = progressMetrics.pct;
  const meta = _arMetaText(stage, adsFound, targetAds, pickedCount, variantsDone, variantsTotal, lastEvent);
  const platformProgressRows = _platformProgressRows(lastEvent, sources);
  const directionGroups = _directionProgressGroups(lastEvent);
  const directionRowsCount = directionGroups.reduce((total, group) => total + group.rows.length, 0);
  const coverageTotal = Number(lastEvent?.coverage_total || 0) || directionRowsCount;
  const coverageTouched = Number(lastEvent?.coverage_touched || 0)
    || directionGroups.reduce((total, group) => total + group.rows.filter(row => row.touched).length, 0);

  const toggleDirection = (id) => {
    setEstimateDirty(true);
    setSelectedDirectionIds(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  };
  const selectAllDirections = () => {
    setEstimateDirty(true);
    setSelectedDirectionIds(new Set(directions.map(d => d.id)));
  };
  const allDirectionsPicked = directions.length > 0 && selectedDirectionIds.size >= directions.length;

  const run = () => {
    onRun({
      mode: 'auto_search',
      directionId: null,
      directionIds: selectedIds,
      count: capNum,
      nVariants: variants,
      platforms: selectedSources,
      maxAdsPerDirection: directionBudget,
      maxAdsPerPlatform: platformBudget,
      strategy: String(strategy || '').trim(),
    });
  };

  return (
    <div className="search-card ar-card">
      <div className="sc-hdr">
        <span className="sc-title">Auto-Remodel</span>
        <span className="sc-sub">One-click crawl, score, filter audit, and remodel</span>
        <div className="sc-actions">
          {onClose && !running && <button className="icon-btn" onClick={onClose} title="Close"><Icon name="x" size={14} /></button>}
        </div>
      </div>

      <div className="ar-sources" style={{ paddingTop: 8, alignItems: 'stretch' }}>
        <label className="ar-target">
          <span>How many ads</span>
          <input type="number" min={1} max={countMax} value={count} onChange={(e) => { setEstimateDirty(true); setCount(e.target.value); }} />
        </label>
        <label className="ar-target" style={{ display: 'none' }}>
          <span>Ads per direction cap</span>
          <input
            type="number"
            min={1}
            max={adsPerDirectionMax}
            value={maxAdsPerDirection}
            placeholder="No cap"
            title={`Maximum ads to fetch per direction and source. Blank leaves direction search uncapped. Max ${adsPerDirectionMax}.`}
            onChange={(e) => { setEstimateDirty(true); setMaxAdsPerDirection(e.target.value); }}
          />
        </label>
        <label className="ar-target" style={{ display: 'none' }}>
          <span>Ads per source cap</span>
          <input
            type="number"
            min={1}
            max={adsPerPlatformMax}
            value={maxAdsPerPlatform}
            placeholder="No cap"
            title={`Maximum ads to fetch per source across this run. Blank leaves the source uncapped. Max ${adsPerPlatformMax}.`}
            onChange={(e) => { setEstimateDirty(true); setMaxAdsPerPlatform(e.target.value); }}
          />
        </label>
        <div className="ar-dirs ar-dirs-inline" ref={pickerRef} style={{ minWidth: 280 }}>
          <button
            type="button"
            className={`ar-dirs-trigger ${selectedIds.length > 0 ? 'active' : ''}`}
            onClick={() => setPickerOpen(o => !o)}
            aria-expanded={pickerOpen}
            aria-haspopup="listbox"
            disabled={busy}
          >
            <span className="ar-dirs-trigger-label">Directions</span>
            <span className="ar-dirs-trigger-value">{pickerLabel}</span>
            <span className={`ar-dirs-chevron ${pickerOpen ? 'up' : ''}`}>
              <Icon name="chevronDown" size={14} />
            </span>
          </button>
          {pickerOpen && (
            <div className="ar-dirs-popover" role="listbox">
              <div className="ar-dirs-popover-head">
                <span className="ar-dirs-popover-hint">
                  {selectedIds.length === 0
                    ? 'No picks -> random directions, including competitors.'
                    : `${selectedIds.length} picked - only these will run.`}
                </span>
                <div className="ar-dirs-actions">
                  {!allDirectionsPicked && (
                    <button className="ar-dirs-clear" onClick={selectAllDirections}>
                      Select all
                    </button>
                  )}
                  {selectedIds.length > 0 && (
                    <button className="ar-dirs-clear" onClick={() => { setEstimateDirty(true); setSelectedDirectionIds(new Set()); }}>
                      Clear
                    </button>
                  )}
                </div>
              </div>
              <div className="ar-dirs-grid">
                {directions.map((d) => {
                  const on = selectedDirectionIds.has(d.id);
                  return (
                    <label key={d.id} className={`ar-dir-pill ${on ? 'on' : 'off'}`} title={typeLabel(d)}>
                      <input
                        type="checkbox"
                        checked={on}
                        onChange={() => toggleDirection(d.id)}
                      />
                      <span className="ar-dir-label">{labelFor(d)}</span>
                      {d.type === 'competitor' && <span style={{ fontSize: 10, opacity: 0.72 }}>competitor</span>}
                    </label>
                  );
                })}
              </div>
            </div>
          )}
          {directions.length > 0 && (
            <div className="ar-dirs-preview" title={selectedDirectionPreview.map(labelFor).join(', ')}>
              {selectedDirectionPreview.slice(0, 6).map(d => (
                <span key={d.id} className="ar-dir-preview-pill">{labelFor(d)}</span>
              ))}
              {selectedDirectionPreview.length > 6 && <span className="ar-dir-preview-more">+{selectedDirectionPreview.length - 6}</span>}
            </div>
          )}
        </div>
        <div className="ar-sources-spacer" />
        {Object.entries(PLATFORMS).map(([key, p]) => {
          const sourceOn = !!sources[key];
          const live = key === 'foreplay' || key === 'adspy' || key === 'brandsearch';
          return (
            <button
              key={key}
              className={`plat-toggle ${sourceOn ? 'on' : 'off'}`}
              onClick={() => {
                if (!live || !onToggleSource) return;
                setEstimateDirty(true);
                onToggleSource(key);
              }}
              style={sourceOn ? { background: p.bg, color: p.color, borderColor: p.bg } : {}}
              title={live ? `Use ${p.label}` : `${p.label} — backend not wired yet`}
              disabled={busy || !live}
            >
              <span className="plat-dot" style={{ background: sourceOn ? p.color : '#b2b8c2' }} />
              {p.label}
            </button>
          );
        })}
        <button
          className="plat-toggle all"
          onClick={() => {
            if (!onSelectAllSources) return;
            setEstimateDirty(true);
            onSelectAllSources();
          }}
          title="Use all live sources"
          disabled={busy}
        >
          All
        </button>
        {running ? (
          <button className="btn-secondary" onClick={() => onStop && onStop()}>
            <Icon name="x" size={14} /> Stop
          </button>
        ) : (
          <button className="btn-primary" onClick={run} disabled={starting || selectedSources.length === 0}>
            <Icon name="bolt" size={14} /> {starting ? 'Starting...' : 'Run Auto-Remodel'}
          </button>
        )}
        {!running && (
          <>
            <button className="btn-secondary" onClick={() => onStop && onStop()} title="Stop Auto-Remodel and fail pending/running script jobs">
              Stop Remodel
            </button>
            <button className="btn-secondary" onClick={() => onRetryFailed && onRetryFailed()} title="Retry failed or stale Auto-Remodel scripts">
              Retry failed
            </button>
          </>
        )}
      </div>

      <label className="ar-target" style={{ display: 'grid', gap: 6, margin: '0 16px 12px' }}>
        <span>Page instructions for the remodeler</span>
        <textarea
          className="t-edit-area"
          value={strategy}
          maxLength={4000}
          onChange={(e) => {
            setEstimateDirty(true);
            if (onStrategyChange) onStrategyChange(e.target.value);
          }}
          placeholder="Optional instructions applied to every Auto-Remodel script in this run."
          style={{ minHeight: 72 }}
        />
      </label>

      <div style={{ padding: '0 16px 12px', color: 'var(--fg-3)', fontSize: 12 }}>
        {estimating && 'Estimating cost...'}
        {!estimating && estimate && (
          <span>Estimated ${estimate.estimated_usd} · ~{estimate.foreplay_credits_estimate} Foreplay credits · {estimate.directions_in_scope} direction{estimate.directions_in_scope === 1 ? '' : 's'}</span>
        )}
        {!estimating && estimateError && <span>{estimateError}</span>}
      </div>

      {(running || stage === 'done' || stage === 'failed' || stage === 'cancelled') && (
        <div className="ar-progress">
          <div className="ar-progress-head">
            {isComplete ? (
              <span className="ar-complete-indicator" aria-hidden="true"><Icon name="check" size={10} /></span>
            ) : (
              <span className={`ar-spinner ${running ? 'spin' : ''}`} />
            )}
            <span className="ar-progress-status">{_arStatusText(stage)}</span>
            {meta && <span className="ar-progress-meta">{meta}</span>}
          </div>
          <div className="ar-progress-bar">
            <div className="ar-progress-fill" style={{ width: `${Math.max(0, Math.min(100, pct))}%` }} />
          </div>
          {platformProgressRows.length > 0 && (
            <div className="ar-platform-progress">
              {platformProgressRows.map(row => (
                <span key={row.platform} className="ar-platform-progress-row">
                  {row.text}
                </span>
              ))}
            </div>
          )}
          {directionGroups.length > 0 && (
            <details className="ar-direction-details">
              <summary>
                Direction details ({coverageTouched}/{coverageTotal || directionRowsCount} searches touched)
              </summary>
              <div className="ar-direction-detail-list">
                {directionGroups.map(group => (
                  <div key={group.key} className="ar-direction-detail-group">
                    <div className="ar-direction-detail-name">{group.name}</div>
                    <div className="ar-direction-detail-platforms">
                      {group.rows.map(row => (
                        <span key={row.key || `${row.direction_id}-${row.source}`} className="ar-direction-detail-row">
                          {_formatDirectionProgressRow(row)}
                        </span>
                      ))}
                    </div>
                  </div>
                ))}
              </div>
            </details>
          )}
        </div>
      )}
    </div>
  );
};
