/* WPSiteBeam Scanner — Images Tab
   Auto-split from Scanner.jsx.
*/
(function () {
  'use strict';
  const ScanEmptyState = window.ScanEmptyState;
  const Icon = window.Icon;

function ScannerImagesTab({ data }) {
  const { useState, useMemo } = React;

  /* Hooks MUST be called unconditionally before any early returns.
     All state + memos declared here; empty-state logic runs after. */
  const [filter, setFilter] = useState('all');
  const [zipping, setZipping] = useState(false);
  const [viewMode, setViewMode] = useState('grid');  /* 'grid' | 'list' */

  const list = Array.isArray(data?.imageList) ? data.imageList : [];

  /* Group by type + derive counts for filter bar */
  const typeCounts = useMemo(() => {
    const c = { all: list.length, logo: 0, icon: 0, hero: 0, thumbnail: 0, image: 0, svg: 0 };
    list.forEach(x => {
      c[x.type] = (c[x.type] || 0) + 1;
      if (x.ext === 'svg') c.svg++;
    });
    return c;
  }, [list]);

  /* Apply filter + A-Z alphabetical sort by filename (case-insensitive).
     Sorting is stable (same filename order across renders) and makes the
     grid scannable by eye — which is the #1 user complaint with unsorted
     image inventories. */
  const filtered = useMemo(() => {
    let r;
    if (filter === 'all') r = list;
    else if (filter === 'svg') r = list.filter(x => x.ext === 'svg');
    else r = list.filter(x => x.type === filter);
    return [...r].sort((a, b) => {
      const aName = (a.filename || '').toLowerCase();
      const bName = (b.filename || '').toLowerCase();
      return aName.localeCompare(bName);
    });
  }, [list, filter]);

  if (!data || !data.site) {
    return <ScanEmptyState tab="images" reason="No scan data available yet." />;
  }

  /* Tri-state empty-state messaging:
       - Server count = 0 AND list empty → truly no images
       - Server count > 0 BUT list empty → count known, extraction failed
       - List populated → render normally (below) */
  if (list.length === 0) {
    if (data.images > 0) {
      return <ScanEmptyState
        tab="images"
        reason={`The scan detected ${data.images} images on this site, but per-image details (URLs, dimensions, alt text) couldn't be extracted. This can happen when the homepage loads images after initial HTML (lazy-load / JavaScript) or when the image-extraction step was interrupted. Re-scanning usually fixes it.`}
      />;
    }
    return <ScanEmptyState
      tab="images"
      reason="No images were discovered on the scanned pages. This could mean the site has no images, uses CSS backgrounds instead of <img> tags, or loads images dynamically via JavaScript after page load."
    />;
  }

  const RAILWAY = (typeof window !== 'undefined' && window.WPSB_API)
    || 'https://wpsitebeam-railway-api-production.up.railway.app';

  function proxyUrl(src, forDownload = false, fn = null) {
    const params = new URLSearchParams({ url: src });
    if (forDownload) params.set('download', '1');
    if (fn) params.set('filename', fn);
    return `${RAILWAY}/proxy/image?${params.toString()}`;
  }

  /* Single-image download via proxy ?download=1 — browser gets Content-Disposition
     attachment header so file saves directly instead of opening inline. */
  function downloadOne(img) {
    const fn = (img.filename || `image-${img.id}.${img.ext || 'jpg'}`).replace(/[<>:"|?*]/g, '_');
    const url = proxyUrl(img.src, true, fn);
    // Use a temporary anchor with download attr (proxy returns attachment header too).
    const a = document.createElement('a');
    a.href = url;
    a.download = fn;
    a.rel = 'noopener';
    document.body.appendChild(a);
    a.click();
    setTimeout(() => document.body.removeChild(a), 200);
    window.wpsbToast?.(`Saving ${fn}`, 'ok');
  }

  /* ZIP all (or filtered subset) via JSZip CDN. Matches v1 downloadAllImages
     flow: load JSZip if absent, fetch each image through Railway proxy (for CORS),
     add to zip folder named {host}-images, save as {host}-images.zip. */
  async function downloadAllAsZip() {
    if (zipping) return;
    setZipping(true);
    try {
      // Load JSZip if not already loaded
      if (typeof window.JSZip === 'undefined') {
        await new Promise((resolve, reject) => {
          const s = document.createElement('script');
          s.src = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js';
          s.onload = resolve;
          s.onerror = () => reject(new Error('Failed to load JSZip from CDN'));
          document.head.appendChild(s);
        });
      }
      const JSZip = window.JSZip;
      const imgs = filtered.slice(0, 200);  /* cap at 200 images */
      if (!imgs.length) {
        window.wpsbToast?.('No images to download', 'warn');
        return;
      }
      window.wpsbToast?.(`Building ZIP (${imgs.length} images)…`, 'ok');
      const zip = new JSZip();
      const host = (data.site || 'site').replace(/[^a-z0-9.-]/gi, '_');
      const folder = zip.folder(`${host}-images`);

      let fetched = 0;
      await Promise.all(imgs.map(async (img) => {
        const fn = (img.filename || `image-${img.id}.${img.ext || 'jpg'}`).replace(/[<>:"|?*]/g, '_');
        try {
          const r = await fetch(proxyUrl(img.src), { mode: 'cors' });
          if (!r.ok) return;
          const blob = await r.blob();
          if (blob.size > 0) {
            folder.file(fn, blob);
            fetched++;
          }
        } catch (e) {
          /* proxy failure — silently skip, continue with others */
        }
      }));

      const zipBlob = await zip.generateAsync({
        type: 'blob',
        compression: 'DEFLATE',
        compressionOptions: { level: 6 },
      });
      const a = document.createElement('a');
      a.href = URL.createObjectURL(zipBlob);
      a.download = `${host}-images.zip`;
      a.style.display = 'none';
      document.body.appendChild(a);
      a.click();
      setTimeout(() => {
        URL.revokeObjectURL(a.href);
        document.body.removeChild(a);
      }, 2000);

      if (fetched === 0) {
        window.wpsbToast?.('No images could be downloaded. Please try again.', 'warn');
      } else {
        window.wpsbToast?.(`Downloaded ${fetched}/${imgs.length} images`, 'ok');
      }
    } catch (e) {
      window.wpsbToast?.(`Download failed: ${e.message}`, 'warn');
    } finally {
      setZipping(false);
    }
  }

  /* Copy URL helper */
  function copyUrl(src) {
    window.wpsbCopy?.(src, 'URL copied');
  }

  /* Filter-bar buttons. Only show types that have entries. */
  const filterTabs = [
    ['all', `All (${typeCounts.all})`],
    ['logo', `Logos (${typeCounts.logo})`],
    ['hero', `Hero (${typeCounts.hero})`],
    ['thumbnail', `Thumbnails (${typeCounts.thumbnail})`],
    ['icon', `Icons (${typeCounts.icon})`],
    ['image', `Other (${typeCounts.image})`],
    ['svg', `SVG (${typeCounts.svg})`],
  ].filter(([k]) => typeCounts[k] > 0 || k === 'all');

  /* ── UI ── */
  const missingAlt = list.filter(x => !x.alt).length;
  const svgCount   = list.filter(x => x.ext === 'svg').length;
  const withDims   = list.filter(x => x.width && x.height).length;

  return (
    <>
      {/* Partial results notice — always shown */}
      <div style={{
        display:'flex', gap:10, alignItems:'flex-start',
        padding:'9px 13px', marginBottom:12,
        background:'var(--orange-dim)',
        border:'1px solid var(--orange-dim)',
        borderRadius:7, fontSize:'.76rem', color:'var(--dim)', lineHeight:1.6,
      }}>
        <span style={{ fontSize:'1rem', flexShrink:0, marginTop:1 }}>⚠</span>
        <span>
          <strong style={{ color:'var(--text)', fontWeight:600 }}>Partial results possible.</strong>
          {' '}Images loaded via JavaScript after page load, inside iframes, or served from restricted/authenticated pages may not appear here.
          Installing the WPSiteBeam plugin on the source site improves detection coverage.
        </span>
      </div>
      {/* Summary card — real stats from actual images */}
      <div className="card" style={{ marginBottom: 14 }}>
        <div className="card-head">
          <h2 className="card-title">Image inventory</h2>
          <span className="tag">{list.length} FOUND</span>
        </div>
        <div className="card-body">
          <div className="grid grid-4">
            <div className="stat">
              <div className="stat-lbl">Total images</div>
              <div className="stat-val">{list.length}</div>
              <div style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginTop:4 }}>
                SVG {svgCount} · Raster {list.length - svgCount}
              </div>
            </div>
            <div className="stat">
              <div className="stat-lbl">Types detected</div>
              <div className="stat-val">{Object.entries(typeCounts).filter(([k,v]) => k !== 'all' && k !== 'svg' && v > 0).length}</div>
              <div style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginTop:4 }}>
                logo/hero/icon/thumbnail/other
              </div>
            </div>
            <div className="stat">
              <div className="stat-lbl">Missing alt text</div>
              <div className="stat-val" style={{ color: missingAlt > 0 ? 'var(--warn)' : 'var(--ok)' }}>{missingAlt}</div>
              <div style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginTop:4 }}>
                {missingAlt > 0 ? 'Fails WCAG 1.1.1' : 'All tagged'}
              </div>
            </div>
            <div className="stat">
              <div className="stat-lbl">With dimensions</div>
              <div className="stat-val" style={{ color: withDims === list.length ? 'var(--ok)' : 'var(--warn)' }}>{withDims}</div>
              <div style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)', marginTop:4 }}>
                {withDims === list.length ? 'All sized' : 'Improves page load'}
              </div>
            </div>
          </div>
          <div style={{ display:'flex', gap:8, marginTop:14, flexWrap:'wrap' }}>
            <button className="btn btn-primary btn-sm" onClick={downloadAllAsZip} disabled={zipping}>
              <Icon name="download" size={13}/>
              {zipping ? 'Building ZIP…' : `Download all as ZIP (${filtered.length})`}
            </button>
            <button className="btn btn-ghost btn-sm" onClick={() => {
              window.wpsbDownload?.(`${data.site}-image-urls.txt`, list.map(i => i.src).join('\n'), 'text/plain');
            }}>
              <Icon name="download" size={12}/>Export URL list
            </button>
          </div>
        </div>
      </div>

      {/* Image grid/list with view toggle + filters */}
      <div className="card">
        <div className="card-head">
          <h2 className="card-title">Images · {filtered.length} shown · A-Z</h2>
          <div style={{ display:'flex', gap:10, flexWrap:'wrap', alignItems:'center' }}>
            {/* View mode toggle — grid vs list. Persists within session. */}
            <div style={{ display:'flex', gap:2, border:'1px solid var(--border)', borderRadius:6, padding:2 }}
                 role="group" aria-label="View mode">
              <button
                type="button"
                onClick={() => setViewMode('grid')}
                aria-pressed={viewMode==='grid'}
                title="Grid view (thumbnails)"
                style={{
                  padding:'4px 10px', fontSize:'.7rem', border:'none', cursor:'pointer',
                  background: viewMode==='grid' ? 'var(--beam-dim)' : 'transparent',
                  color: viewMode==='grid' ? 'var(--beam)' : 'var(--dim)',
                  borderRadius:4, fontFamily:'var(--font-mono)',
                }}
              >▦ Grid</button>
              <button
                type="button"
                onClick={() => setViewMode('list')}
                aria-pressed={viewMode==='list'}
                title="List view (compact rows)"
                style={{
                  padding:'4px 10px', fontSize:'.7rem', border:'none', cursor:'pointer',
                  background: viewMode==='list' ? 'var(--beam-dim)' : 'transparent',
                  color: viewMode==='list' ? 'var(--beam)' : 'var(--dim)',
                  borderRadius:4, fontFamily:'var(--font-mono)',
                }}
              >☰ List</button>
            </div>
            {/* Filter type chips */}
            <div style={{ display:'flex', gap:6, flexWrap:'wrap' }} role="group" aria-label="Image type filters">
              {filterTabs.map(([k, l]) => (
                <button key={k}
                        className={'btn btn-ghost btn-sm' + (filter===k?' active':'')}
                        aria-pressed={filter===k}
                        style={filter===k ? { background:'var(--beam-dim)', color:'var(--beam)', borderColor:'var(--beam-dim)' } : null}
                        onClick={() => setFilter(k)}>
                  {l}
                </button>
              ))}
            </div>
          </div>
        </div>
        <div className="card-body">
          <div style={{ fontSize:'.72rem', color:'var(--dim)', marginBottom:10, fontFamily:'var(--font-mono)' }}>
            {viewMode === 'grid'
              ? 'Click a tile to copy its URL · hover for actions'
              : 'Sorted A-Z · click a row to copy its URL'}
          </div>

          {filtered.length === 0 && <div style={{ color:'var(--dim)', fontSize:'.8rem' }}>No images match this filter.</div>}

          {/* LIST VIEW — compact rows, no thumbnails. Good for 50+ images. */}
          {viewMode === 'list' && filtered.length > 0 && (
            <div style={{ border:'1px solid var(--border)', borderRadius:6, overflow:'hidden' }}>
              <div style={{
                display:'grid', gridTemplateColumns:'1fr 80px 100px 100px 150px',
                gap:10, padding:'8px 12px',
                background:'var(--surface-2)', fontSize:'.64rem', fontFamily:'var(--font-mono)',
                color:'var(--dim)', textTransform:'uppercase', letterSpacing:'.05em',
                borderBottom:'1px solid var(--border)',
              }}>
                <span>Filename</span>
                <span>Type</span>
                <span>Size</span>
                <span>Alt text</span>
                <span style={{ textAlign:'right' }}>Actions</span>
              </div>
              {filtered.map((img, idx) => (
                <div key={img.id}
                     onClick={() => copyUrl(img.src)}
                     style={{
                       display:'grid', gridTemplateColumns:'1fr 80px 100px 100px 150px',
                       gap:10, padding:'8px 12px', alignItems:'center',
                       cursor:'pointer', fontSize:'.76rem',
                       background: idx % 2 === 0 ? 'transparent' : 'var(--surface-2, rgba(255,255,255,0.02))',
                       borderBottom: idx < filtered.length - 1 ? '1px solid var(--border)' : 'none',
                     }}
                     title={`Click to copy: ${img.src}`}>
                  <span style={{ fontFamily:'var(--font-mono)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
                    {img.filename}
                  </span>
                  <span style={{ fontFamily:'var(--font-mono)', fontSize:'.68rem', color:'var(--dim)', textTransform:'uppercase' }}>
                    {img.ext || img.type}
                  </span>
                  <span style={{ fontFamily:'var(--font-mono)', fontSize:'.7rem', color:'var(--dim)' }}>
                    {(img.width && img.height) ? `${img.width}×${img.height}` : '—'}
                  </span>
                  <span style={{ fontSize:'.7rem', color: img.alt ? 'var(--text)' : 'var(--warn)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}
                        title={img.alt || 'Missing alt text'}>
                    {img.alt || '⚠ missing'}
                  </span>
                  <span style={{ display:'flex', gap:4, justifyContent:'flex-end' }}>
                    <button className="btn btn-ghost btn-sm" style={{ padding:'2px 8px', fontSize:'.64rem' }}
                            onClick={(e) => { e.stopPropagation(); downloadOne(img); }}
                            title={`Download ${img.filename}`}>
                      <Icon name="download" size={10}/>Save
                    </button>
                    <button className="btn btn-ghost btn-sm" style={{ padding:'2px 8px', fontSize:'.64rem' }}
                            onClick={(e) => { e.stopPropagation(); window.open(img.src, '_blank', 'noopener,noreferrer'); }}
                            title="Open source URL in new tab">
                      ↗
                    </button>
                  </span>
                </div>
              ))}
            </div>
          )}

          {/* GRID VIEW — thumbnails, default for visual browsing. */}
          {viewMode === 'grid' && filtered.length > 0 && (
            <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill,minmax(160px,1fr))', gap:12 }}>
              {filtered.map(img => (
                <div key={img.id}
                     style={{ border:'1px solid var(--border)', borderRadius:8, overflow:'hidden', background:'var(--surface)', display:'flex', flexDirection:'column' }}>
                  {/* Thumbnail */}
                  <div style={{ aspectRatio:'1 / 1', background:'var(--surface-2)', position:'relative', overflow:'hidden', cursor:'pointer' }}
                       onClick={() => copyUrl(img.src)}
                       title={`Click to copy URL · ${img.alt || img.filename}`}>
                    <img src={proxyUrl(img.src)}
                         alt={img.alt || img.filename}
                         loading="lazy"
                         style={{ width:'100%', height:'100%', objectFit:'contain', display:'block' }}
                         onError={(e) => {
                           e.currentTarget.style.display = 'none';
                           e.currentTarget.parentElement.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:var(--dim);font-size:.7rem;padding:8px;text-align:center">Image could not load</div>';
                         }}/>
                    {/* Type badge */}
                    <span style={{
                      position:'absolute', top:6, left:6,
                      fontSize:'.58rem', fontFamily:'var(--font-mono)',
                      background:'rgba(0,0,0,.65)', color:'#fff', padding:'2px 6px',
                      borderRadius:3, textTransform:'uppercase', letterSpacing:'.04em',
                    }}>{img.ext || img.type}</span>
                  </div>
                  {/* Info + actions */}
                  <div style={{ padding:8, display:'flex', flexDirection:'column', gap:6 }}>
                    <div style={{ fontSize:'.7rem', fontFamily:'var(--font-mono)', color:'var(--text)',
                                  overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}
                         title={img.filename}>{img.filename}</div>
                    <div style={{ display:'flex', gap:4 }}>
                      <button className="btn btn-ghost btn-sm" style={{ padding:'3px 8px', fontSize:'.68rem', flex:1 }}
                              onClick={(e) => { e.stopPropagation(); downloadOne(img); }}
                              title={`Download ${img.filename}`}>
                        <Icon name="download" size={11}/>Save
                      </button>
                      <button className="btn btn-ghost btn-sm" style={{ padding:'3px 8px', fontSize:'.68rem' }}
                              onClick={(e) => { e.stopPropagation(); window.open(img.src, '_blank', 'noopener,noreferrer'); }}
                              title="Open source URL in new tab">
                        ↗
                      </button>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>
    </>
  );
}

/* ── FILES & DOCUMENTS TAB ──────────────────────────────────────────
   Crawler enumerates /wp-content/uploads/ and every <a href> / <img src>
   pointing at a document. Flags: bad-name (caps/spaces/diacritics),
   oversize (>2MB), ada (no-ocr, no-alt, scanned-image-pdf), orphan (referenced
   by no page), duplicate (near-duplicate filename/hash), broken (404 on HEAD).
   "Send to File Map" pushes selection → Redirects → File Map. */

window.ScannerImagesTab = ScannerImagesTab;
})();
