// Forge — Dossier hero schematics + data loader.
// Case data is fetched at runtime from forge-portfolio-cases.json.
// The `id` field in the JSON matches the URL hash slug:
//   dossier.html#tile-pipeline-rebuild

// ---------- shared frame ----------
const HeroFrame = ({ children, label, rightLabel }) => (
  <svg viewBox="0 0 1080 320" width="100%" height="auto"
       preserveAspectRatio="xMidYMid meet" style={{display: 'block'}}>
    <rect width="1080" height="320" fill="#14161a"/>
    <g stroke="rgba(255,255,255,0.05)" strokeWidth="0.5">
      {Array.from({length: 28}).map((_, i) => <line key={'v'+i} x1={i*40} y1="0" x2={i*40} y2="320"/>)}
      {Array.from({length: 9}).map((_, i) => <line key={'h'+i} x1="0" y1={i*40} x2="1080" y2={i*40}/>)}
    </g>
    {[[16,16],[1064,16],[16,304],[1064,304]].map(([x,y], i) => (
      <g key={i} stroke="#e8623a" strokeWidth="1">
        <line x1={x-6} y1={y} x2={x+6} y2={y}/>
        <line x1={x} y1={y-6} x2={x} y2={y+6}/>
      </g>
    ))}
    {children}
    <g fontFamily="JetBrains Mono, monospace" fontSize="10" fill="#a4abb5" letterSpacing="1.5">
      <text x="36" y="28">{label}</text>
      <text x="1044" y="28" textAnchor="end">{rightLabel}</text>
    </g>
  </svg>
);

// ---------- hero · boreal canopy ----------
const HeroCanopy = () => (
  <HeroFrame label="CANOPY · LIDAR · σ ≤ 0.018 M" rightLabel="N 49°00′ — W 71°00′">
    <g stroke="#a4abb5" strokeWidth="0.9" fill="none" opacity="0.7">
      {Array.from({length: 9}).map((_, i) => (
        <path key={i} d={`M 0 ${260 - i*22} Q 180 ${220 - i*22} 360 ${240 - i*22} T 720 ${214 - i*22} T 1080 ${224 - i*22}`}/>
      ))}
    </g>
    <g stroke="#e8623a" strokeWidth="1.4" fill="none">
      <path d="M 0 60 Q 180 30 360 50 T 720 22 T 1080 30"/>
    </g>
    {[[80,250],[180,236],[280,224],[380,214],[490,206],[600,200],[720,196],[850,190],[980,184]].map(([x,y], i) => (
      <g key={i} stroke="#e8623a" strokeWidth="1">
        <line x1={x} y1={y-5} x2={x} y2={y+5}/>
        <line x1={x-5} y1={y} x2={x+5} y2={y}/>
      </g>
    ))}
    <g stroke="#a4abb5" strokeWidth="1" fill="none">
      <line x1="40" y1="290" x2="200" y2="290"/>
      <line x1="40" y1="286" x2="40" y2="294"/>
      <line x1="120" y1="288" x2="120" y2="292"/>
      <line x1="200" y1="286" x2="200" y2="294"/>
    </g>
    <text x="40" y="282" fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="1">0 — 10 KM</text>
  </HeroFrame>
);

// ---------- hero · tile pipeline ----------
const HeroTiles = () => (
  <HeroFrame label="MVT PYRAMID · Z 4–16" rightLabel="BLOB-CACHED · 30 MS P95">
    {(() => {
      const out = [];
      for (let lvl = 0; lvl < 6; lvl++) {
        const count = lvl + 1, size = 26, gap = 5;
        const totalW = count * size + (count - 1) * gap;
        const startX = 540 - totalW / 2;
        const y = 48 + lvl * 32;
        for (let i = 0; i < count; i++) {
          const isHot = lvl === 2 && i === 1;
          out.push(
            <rect key={`${lvl}-${i}`}
                  x={startX + i * (size + gap)} y={y}
                  width={size} height={size}
                  fill={isHot ? '#e8623a' : '#262a31'}
                  stroke="rgba(255,255,255,0.18)" strokeWidth="0.8"/>
          );
        }
      }
      return out;
    })()}
    <g fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="1">
      {[0,1,2,3,4,5].map((lvl, i) => (
        <text key={i} x="60" y={64 + lvl * 32}>Z = {4 + lvl}</text>
      ))}
    </g>
    <g stroke="#e8623a" strokeWidth="0.9" fill="none" opacity="0.85">
      <line x1="566" y1="106" x2="840" y2="106"/>
      <line x1="840" y1="106" x2="840" y2="76"/>
      <line x1="836" y1="76" x2="844" y2="76"/>
    </g>
    <text x="840" y="68" fontFamily="JetBrains Mono, monospace" fontSize="10"
          fill="#e8623a" textAnchor="middle" letterSpacing="1">CACHED TILE</text>
    <g transform="translate(0, 268)">
      <line x1="36" y1="0" x2="1044" y2="0" stroke="rgba(255,255,255,0.12)" strokeWidth="0.6"/>
      {[
        [60,   'POSTGIS'],
        [310,  'ST_AsMVT'],
        [560,  'BLOB CACHE'],
        [820,  'MAPLIBRE'],
      ].map(([x, label], i, arr) => (
        <g key={label}>
          <rect x={x-4} y={-4} width="8" height="8"
                fill={i === 2 ? '#e8623a' : '#1c1f24'}
                stroke={i === 2 ? '#e8623a' : '#6e7681'} strokeWidth="1"/>
          <text x={x} y={22} fontFamily="JetBrains Mono, monospace" fontSize="9"
                fill="#a4abb5" textAnchor="middle" letterSpacing="1.5">{label}</text>
          {i < arr.length - 1 && (
            <line x1={x + 12} y1="0" x2={arr[i+1][0] - 12} y2="0" stroke="#6e7681" strokeWidth="0.8"/>
          )}
        </g>
      ))}
    </g>
  </HeroFrame>
);

// ---------- hero · DL road extraction benchmark ----------
const HeroBench = () => {
  let s = 7;
  const r = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };

  const drawNetwork = (cx, ox, oy, color, noise, strokeW) => {
    const segs = [
      [10, 30, 200, 50], [40, 80, 210, 70], [10, 120, 180, 130],
      [60, 30, 90, 130], [130, 50, 160, 140], [180, 60, 200, 150],
    ];
    return segs.map(([x1,y1,x2,y2], i) => {
      if (noise > 0.6 && i === 2) return null;
      if (noise > 0.4 && i === 5) return null;
      const dx1 = (r() - 0.5) * noise * 8, dy1 = (r() - 0.5) * noise * 8;
      const dx2 = (r() - 0.5) * noise * 8, dy2 = (r() - 0.5) * noise * 8;
      return <line key={`${cx}-${i}`}
                   x1={ox + x1 + dx1} y1={oy + y1 + dy1}
                   x2={ox + x2 + dx2} y2={oy + y2 + dy2}
                   stroke={color} strokeWidth={strokeW} opacity="0.9"/>;
    }).filter(Boolean);
  };

  const Method = ({ x, title, code, accent, noise, f1, apls }) => (
    <g>
      <rect x={x} y="64" width="240" height="180" fill="#1c1f24" stroke="rgba(255,255,255,0.16)" strokeWidth="0.8"/>
      <g opacity="0.18">
        {Array.from({length: 12}).map((_, i) => (
          <rect key={i} x={x + 8 + ((i * 19) % 220)} y={72 + ((i * 31) % 160)}
                width="14" height="14" fill="#6e7681"/>
        ))}
      </g>
      {drawNetwork(x, x + 10, 70, accent, noise, 1.3)}
      <text x={x + 12} y="58" fontFamily="JetBrains Mono, monospace" fontSize="10"
            fill={accent} letterSpacing="1.5">{title}</text>
      <text x={x + 228} y="58" fontFamily="JetBrains Mono, monospace" fontSize="9"
            fill="#a4abb5" textAnchor="end" letterSpacing="1">{code}</text>
      <g fontFamily="JetBrains Mono, monospace" fontSize="11" letterSpacing="0.06em">
        <text x={x + 12} y="264" fill="#a4abb5">F1</text>
        <text x={x + 60} y="264" fill={accent}>{f1}</text>
        <text x={x + 120} y="264" fill="#a4abb5">APLS</text>
        <text x={x + 180} y="264" fill={accent}>{apls}</text>
      </g>
    </g>
  );

  return (
    <HeroFrame label="ROAD EXTRACTION · 3 METHODS" rightLabel="CNN + POST WINS · +14 % F1">
      <Method x={60}  title="CNN"        code="R2AUnet" accent="#a4abb5" noise={0.5}  f1="0.74" apls="0.69"/>
      <Method x={420} title="CNN + POST" code="WINNER"  accent="#e8623a" noise={0.18} f1="0.85" apls="0.78"/>
      <Method x={780} title="GRAPH"      code="GTE"     accent="#a4abb5" noise={0.85} f1="0.72" apls="0.65"/>
      <g fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="1">
        <text x="540" y="296" textAnchor="middle">SAME 50-CM IMAGERY · ~12,684 KM² · ~28,060 KM ROADS</text>
      </g>
    </HeroFrame>
  );
};

// ---------- hero · rangers patrol ----------
const HeroField = () => (
  <HeroFrame label="PATROL · NORD-DU-QUEBEC" rightLabel="OFFLINE · QFIELD">
    <path d="M 90 70 L 880 56 L 1000 130 L 980 240 L 820 290 L 280 280 L 100 220 Z"
          fill="none" stroke="#6e7681" strokeWidth="1.1" strokeDasharray="4 4"/>
    <g stroke="#6e7681" strokeWidth="0.9" fill="none" opacity="0.4">
      <path d="M 200 100 C 320 130 420 150 540 160 C 660 170 760 150 880 170"/>
      <path d="M 540 160 C 540 200 600 230 700 250"/>
    </g>
    <path d="M 200 130 C 280 152 360 178 460 184 C 580 192 660 158 760 174 C 860 192 800 240 700 252 C 580 264 500 226 420 220 C 320 212 260 188 220 200"
          fill="none" stroke="#d8dde3" strokeWidth="1.5"/>
    {[[200,130],[360,178],[560,188],[760,174],[700,252],[460,224],[280,196]].map(([x,y], i) => (
      <g key={i}>
        <rect x={x-5} y={y-5} width="10" height="10" fill="#14161a" stroke="#e8623a" strokeWidth="1.2"/>
        <text x={x+12} y={y+3} fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5">{String(i+1).padStart(2,'0')}</text>
      </g>
    ))}
    <g transform="translate(960, 100)" stroke="#a4abb5" strokeWidth="0.8" fill="none">
      <line x1="0" y1="-16" x2="0" y2="14"/>
      <polygon points="0,-16 -4,-8 4,-8" fill="#a4abb5" stroke="none"/>
    </g>
    <text x="955" y="134" fontFamily="JetBrains Mono, monospace" fontSize="10" fill="#a4abb5">N</text>
    <text x="36" y="294" fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="1">
      PATROL CYCLE · 3–10 DAYS
    </text>
  </HeroFrame>
);

// ---------- hero · wastewater hydrography ----------
const HeroHydro = () => (
  <HeroFrame label="QUEBEC HYDRO NETWORK" rightLabel="DISCHARGE EVENTS · PROVINCE-WIDE">
    <path d="M 0 170 C 160 180 280 220 480 200 S 820 248 1080 218"
          stroke="#6e7681" strokeWidth="3" fill="none" opacity="0.6"/>
    <g stroke="#6e7681" strokeWidth="1.6" fill="none" opacity="0.45">
      <path d="M 80 10 C 120 60 160 100 200 196"/>
      <path d="M 220 0 C 240 60 260 130 290 204"/>
      <path d="M 400 0 C 410 60 420 130 460 200"/>
      <path d="M 560 8 C 570 70 590 130 620 208"/>
      <path d="M 720 0 C 720 80 700 130 670 216"/>
      <path d="M 880 6 C 880 70 860 140 830 224"/>
      <path d="M 1000 14 C 990 80 960 150 920 228"/>
    </g>
    <g stroke="#6e7681" strokeWidth="1.3" fill="none" opacity="0.35">
      <path d="M 140 310 C 160 270 200 230 220 200"/>
      <path d="M 360 310 C 380 270 400 230 410 204"/>
      <path d="M 580 310 C 600 270 610 230 608 210"/>
      <path d="M 820 310 C 830 270 830 240 830 226"/>
    </g>
    {[[120,178],[228,200],[290,206],[378,196],[460,202],[540,210],[620,212],[730,222],[830,226],[930,222]].map(([x,y], i) => (
      <rect key={i} x={x-4} y={y-4} width="8" height="8" fill="#e8623a"/>
    ))}
    <g fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="1">
      <rect x="36" y="290" width="8" height="8" fill="#e8623a"/>
      <text x="52" y="298">DISCHARGE EVENT</text>
      <line x1="200" y1="294" x2="226" y2="294" stroke="#6e7681" strokeWidth="2"/>
      <text x="234" y="298">HYDRO SEGMENT</text>
    </g>
  </HeroFrame>
);

// ---------- hero · discharge dashboards (k-032) ----------
const HeroDashboards = () => {
  const p1 = { x: 36,  y: 44, w: 318, h: 198 };
  const p2 = { x: 368, y: 44, w: 318, h: 198 };
  const p3 = { x: 700, y: 44, w: 344, h: 198 };

  const barBaseline = p1.y + p1.h - 24;
  const barHeights  = [54, 72, 94, 136, 88, 62];
  const barW = 32, barSpacing = 46, barStart = p1.x + 32;

  const pts = [
    [p2.x + 28,  p2.y + 158],
    [p2.x + 74,  p2.y + 144],
    [p2.x + 120, p2.y + 120],
    [p2.x + 166, p2.y + 112],
    [p2.x + 212, p2.y + 98 ],
    [p2.x + 258, p2.y + 108],
    [p2.x + 290, p2.y + 118],
  ];
  const baseLine = p2.y + p2.h - 32;

  const sevs = [
    ['ST-LAURENT', 'MODERATE', false],
    ['RICHELIEU',  'SEVERE',   true ],
    ['CHAUDIÈRE',  'MINOR',    false],
    ['YAMASKA',    'MODERATE', false],
    ['OUTAOUAIS',  'SEVERE',   true ],
  ];
  const sevRowH = (p3.h - 32) / sevs.length;

  const pipeY = 278;
  const nodes = [
    [100, 'POSTGIS',          false],
    [370, 'POWER QUERY',      false],
    [650, 'POWER BI SERVICE', true ],
    [920, 'PARTNERS',         false],
  ];

  return (
    <HeroFrame label="DISCHARGE DASHBOARDS · POWER BI" rightLabel="SELF-SERVE · NGO + PARTNERS">

      {/* Panel 1 – BY MUNICIPALITY */}
      <rect x={p1.x} y={p1.y} width={p1.w} height={p1.h}
            fill="#1c1f24" stroke="rgba(255,255,255,0.16)" strokeWidth="0.8"/>
      <text x={p1.x + 10} y={p1.y + 14}
            fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="2">
        BY MUNICIPALITY
      </text>
      {barHeights.map((h, i) => (
        <rect key={i}
              x={barStart + i * barSpacing} y={barBaseline - h}
              width={barW} height={h}
              fill={i === 3 ? '#e8623a' : '#363b44'}/>
      ))}

      {/* Panel 2 – BY WATERWAY */}
      <rect x={p2.x} y={p2.y} width={p2.w} height={p2.h}
            fill="#1c1f24" stroke="rgba(255,255,255,0.16)" strokeWidth="0.8"/>
      <text x={p2.x + 10} y={p2.y + 14}
            fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="2">
        BY WATERWAY
      </text>
      <line x1={p2.x + 16} y1={baseLine} x2={p2.x + p2.w - 16} y2={baseLine}
            stroke="#6e7681" strokeWidth="0.8"/>
      <polyline points={pts.map(([x, y]) => `${x},${y}`).join(' ')}
                fill="none" stroke="#e8623a" strokeWidth="1.4"/>
      {pts.map(([x, y], i) => (
        <rect key={i} x={x - 3} y={y - 3} width="6" height="6" fill="#e8623a"/>
      ))}

      {/* Panel 3 – BY SEVERITY CLASS */}
      <rect x={p3.x} y={p3.y} width={p3.w} height={p3.h}
            fill="#1c1f24" stroke="rgba(255,255,255,0.16)" strokeWidth="0.8"/>
      <text x={p3.x + 10} y={p3.y + 14}
            fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="2">
        BY SEVERITY CLASS
      </text>
      {sevs.map(([name, level, ember], i) => {
        const ry       = p3.y + 28 + i * sevRowH;
        const sqCol    = ember ? '#e8623a' : '#4a5260';
        const nameCol  = ember ? '#e8623a' : '#a4abb5';
        const lvlCol   = level === 'SEVERE' ? '#e8623a' : level === 'MINOR' ? '#4a5260' : '#a4abb5';
        return (
          <g key={i}>
            <line x1={p3.x + 10} y1={ry} x2={p3.x + p3.w - 10} y2={ry}
                  stroke="rgba(255,255,255,0.06)" strokeWidth="0.6"/>
            <rect x={p3.x + 10} y={ry + 6} width="8" height="8" fill={sqCol}/>
            <text x={p3.x + 26} y={ry + 14}
                  fontFamily="JetBrains Mono, monospace" fontSize="9" fill={nameCol} letterSpacing="1.2">
              {name}
            </text>
            <text x={p3.x + p3.w - 10} y={ry + 14}
                  fontFamily="JetBrains Mono, monospace" fontSize="9" fill={lvlCol} textAnchor="end" letterSpacing="1.5">
              {level}
            </text>
          </g>
        );
      })}

      {/* Pipeline strip */}
      <line x1="36" y1={pipeY} x2="1044" y2={pipeY} stroke="rgba(255,255,255,0.12)" strokeWidth="0.6"/>
      {nodes.map(([x, label, hot], i, arr) => (
        <g key={label}>
          <rect x={x - 4} y={pipeY - 4} width="8" height="8"
                fill={hot ? '#e8623a' : '#1c1f24'}
                stroke={hot ? '#e8623a' : '#6e7681'} strokeWidth="1"/>
          <text x={x} y={pipeY + 18}
                fontFamily="JetBrains Mono, monospace" fontSize="9"
                fill="#a4abb5" textAnchor="middle" letterSpacing="1.5">
            {label}
          </text>
          {i < arr.length - 1 && (
            <line x1={x + 12} y1={pipeY} x2={arr[i + 1][0] - 12} y2={pipeY}
                  stroke="#6e7681" strokeWidth="0.8"/>
          )}
        </g>
      ))}
    </HeroFrame>
  );
};

// ---------- hero · WISP network ----------
const HeroNetwork = () => (
  <HeroFrame label="WISP · NETWORK TOPOLOGY" rightLabel="3 YR · FRACTIONAL STEWARDSHIP">
    {[[180,120,80],[420,160,100],[680,110,70],[340,240,84],[620,250,76],[860,200,86]].map(([x,y,r], i) => (
      <circle key={i} cx={x} cy={y} r={r} fill="none" stroke="#6e7681" strokeWidth="0.8" strokeDasharray="3 3" opacity="0.55"/>
    ))}
    <g stroke="#a4abb5" strokeWidth="1" fill="none" opacity="0.7">
      <line x1="180" y1="120" x2="420" y2="160"/>
      <line x1="420" y1="160" x2="680" y2="110"/>
      <line x1="420" y1="160" x2="340" y2="240"/>
      <line x1="420" y1="160" x2="620" y2="250"/>
      <line x1="680" y1="110" x2="860" y2="200"/>
      <line x1="620" y1="250" x2="860" y2="200"/>
    </g>
    {[[180,120,'AP-01'],[420,160,'AP-HUB'],[680,110,'AP-03'],[340,240,'AP-04'],[620,250,'AP-05'],[860,200,'AP-06']].map(([x,y,label], i) => (
      <g key={i}>
        <rect x={x-6} y={y-6} width="12" height="12" fill="#14161a" stroke="#e8623a" strokeWidth="1.4"/>
        {label === 'AP-HUB' && <line x1={x} y1={y-18} x2={x} y2={y-6} stroke="#e8623a" strokeWidth="1"/>}
        <text x={x} y={y+24} fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" textAnchor="middle" letterSpacing="1">{label}</text>
      </g>
    ))}
    <text x="36" y="294" fontFamily="JetBrains Mono, monospace" fontSize="9" fill="#a4abb5" letterSpacing="1">
      2016 → 2019 · REGIONAL COVERAGE
    </text>
  </HeroFrame>
);

// =====================================================================
// DATA LOADER
// Reads directly from window.FORGE.projects (content.js).
// All dossier content lives in the `dossier` sub-object on each project.
// =====================================================================
const HERO_MAP = {
  'boreal-canopy-structure-model':           HeroCanopy,
  'tile-pipeline-rebuild':                   HeroTiles,
  'deep-learning-road-extraction-benchmark': HeroBench,
  'rangers-operational-capabilities':        HeroField,
  'wastewater-discharge-monitoring-quebec':  HeroHydro,
  'wastewater-discharge-dashboards':         HeroDashboards,
  'wisp-asset-management-network':           HeroNetwork,
};

window.DOSSIER_CASES_PROMISE = Promise.resolve(
  (window.FORGE.projects || []).map((p) => {
    const d = p.dossier || {};
    return {
      slug:         p.slug,
      code:         p.code,
      year:         p.year,
      lab:          p.lab,
      title:        p.title,
      sector:       d.sector       || '',
      client_type:  p.client       || '',
      offers:       p.scope ? p.scope.split(' · ') : [],
      Hero:         HERO_MAP[p.slug] || HeroCanopy,
      problem:      d.problem      || '',
      approach:     d.approach     || '',
      stack:        d.stack        || [],
      deliverables: d.deliverables || [],
      data_volume:  d.data_volume  || '',
      duration:     d.duration     || '',
      key_metric:   d.key_metric   || { value: '', label: '' },
      outcome:      d.outcome      || '',
      published:    d.published    || null,
    };
  })
);
