/* global React */
const { useState: useChartState, useEffect: useChartEffect, useRef: useChartRef } = React;

// City -> approximate lat/lng for US dot map projection
window.VRB_CITY_GEO = {
  "Houston, TX": [29.76, -95.37],
  "Phoenix, AZ": [33.45, -112.07],
  "Atlanta, GA": [33.75, -84.39],
  "Columbus, OH": [39.96, -82.99],
  "Tampa, FL": [27.95, -82.46],
  "Dallas, TX": [32.78, -96.80],
  "Nashville, TN": [36.16, -86.78],
  "Indianapolis, IN": [39.77, -86.16],
  "Charlotte, NC": [35.23, -80.84],
  "Las Vegas, NV": [36.17, -115.14],
  "Kansas City, MO": [39.10, -94.58],
  "Jacksonville, FL": [30.33, -81.66]
};

// Hook: trigger when in viewport (once)
function useInView(threshold = 0.2) {
  const ref = useChartRef(null);
  const [seen, setSeen] = useChartState(false);
  useChartEffect(() => {
    const el = ref.current;
    if (!el) return;
    const obs = new IntersectionObserver(entries => {
      entries.forEach(e => {
        if (e.isIntersecting) { setSeen(true); obs.disconnect(); }
      });
    }, { threshold });
    obs.observe(el);
    return () => obs.disconnect();
  }, [threshold]);
  return [ref, seen];
}

// ============ VINTAGE WATERFALL ============
// One bar per resolved deal, ordered chronologically. Bar height = gross IRR.
// Bars color-coded by asset type. Y axis 0–40%, gridlines at every 10%.
window.VintageWaterfall = function VintageWaterfall() {
  const [ref, seen] = useInView(0.25);
  const deals = window.TrackRecord
    .filter(d => d.status === "Resolved")
    .map(d => ({ ...d, year: parseInt(d.id.split("-")[1], 10), month: parseInt(d.id.split("-")[2], 10) }))
    .sort((a, b) => (a.year * 100 + a.month) - (b.year * 100 + b.month));

  const W = 980, H = 360, padL = 56, padR = 24, padT = 28, padB = 60;
  const innerW = W - padL - padR;
  const innerH = H - padT - padB;
  const yMax = 40;
  const barW = Math.min(64, (innerW - 12 * (deals.length - 1)) / deals.length);
  const colorByType = {
    "Residential": "var(--vrb-blue)",
    "Multifamily": "var(--vrb-navy)",
    "Hospitality": "var(--vrb-green)"
  };

  return (
    <div className="vrb-chart" ref={ref}>
      <div className="chart-head">
        <div>
          <div className="eyebrow">Figure 01</div>
          <h3>Realized gross IRR · vintage waterfall</h3>
        </div>
        <div className="chart-legend">
          <span><i style={{background:"var(--vrb-blue)"}}></i>Residential</span>
          <span><i style={{background:"var(--vrb-navy)"}}></i>Multifamily</span>
          <span><i style={{background:"var(--vrb-green)"}}></i>Hospitality</span>
        </div>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} className="chart-svg" role="img" aria-label="Vintage waterfall: realized gross IRR by acquisition vintage">
        {/* Y gridlines */}
        {[0, 10, 20, 30, 40].map(v => {
          const y = padT + innerH - (v / yMax) * innerH;
          return (
            <g key={v}>
              <line x1={padL} x2={W - padR} y1={y} y2={y}
                stroke="var(--vrb-ink-200)" strokeWidth={v === 0 ? 1.5 : 1}
                strokeDasharray={v === 0 ? "" : "2 4"} />
              <text x={padL - 10} y={y + 4} fontFamily="var(--font-mono)" fontSize="10"
                fill="var(--vrb-ink-500)" textAnchor="end">{v}%</text>
            </g>
          );
        })}
        {/* Bars */}
        {deals.map((d, i) => {
          const x = padL + i * (barW + 12) + (innerW - (deals.length * barW + (deals.length - 1) * 12)) / 2;
          const targetH = (d.irr / yMax) * innerH;
          const h = seen ? targetH : 0;
          const y = padT + innerH - h;
          return (
            <g key={d.id} style={{ transition: `all 900ms cubic-bezier(.2,.8,.2,1) ${i * 80}ms` }}>
              <rect x={x} y={y} width={barW} height={h} fill={colorByType[d.type]} opacity={seen ? 1 : 0}
                style={{ transition: `all 900ms cubic-bezier(.2,.8,.2,1) ${i * 80}ms` }} />
              {/* IRR label on top */}
              <text x={x + barW / 2} y={y - 8}
                fontFamily="var(--font-mono)" fontSize="11" fontWeight="600"
                fill="var(--vrb-navy)" textAnchor="middle"
                opacity={seen ? 1 : 0}
                style={{ transition: `opacity 600ms ease ${800 + i * 80}ms` }}>
                {d.irr.toFixed(1)}
              </text>
              {/* Vintage label */}
              <text x={x + barW / 2} y={padT + innerH + 18}
                fontFamily="var(--font-mono)" fontSize="9.5"
                fill="var(--vrb-ink-500)" textAnchor="middle" letterSpacing="0.04em">
                {d.year}·{String(d.month).padStart(2, "0")}
              </text>
              <text x={x + barW / 2} y={padT + innerH + 32}
                fontFamily="var(--font-mono)" fontSize="9"
                fill="var(--vrb-ink-400)" textAnchor="middle" letterSpacing="0.04em">
                {d.loc.split(",")[1].trim()}
              </text>
            </g>
          );
        })}
        {/* Y axis label */}
        <text x={16} y={padT - 8}
          fontFamily="var(--font-mono)" fontSize="10" fontWeight="600"
          fill="var(--vrb-ink-500)" letterSpacing="0.08em">GROSS IRR (%)</text>
      </svg>
      <p className="chart-caption">
        Each bar represents one resolved transaction. Vintage labels indicate acquisition month / year. All resolutions delivered positive principal recovery; weighted average gross IRR across resolved positions is {(deals.reduce((s, d) => s + d.irr, 0) / deals.length).toFixed(1)}%.
      </p>
    </div>
  );
};

// ============ HOLD × IRR SCATTER ============
window.HoldIrrScatter = function HoldIrrScatter() {
  const [ref, seen] = useInView(0.2);
  const deals = window.TrackRecord.filter(d => d.status === "Resolved");

  const W = 980, H = 420, padL = 56, padR = 32, padT = 32, padB = 60;
  const innerW = W - padL - padR;
  const innerH = H - padT - padB;
  const xMax = 25, yMax = 40;
  const colorByType = {
    "Residential": "var(--vrb-blue)",
    "Multifamily": "var(--vrb-navy)",
    "Hospitality": "var(--vrb-green)"
  };

  const xScale = (mo) => padL + (mo / xMax) * innerW;
  const yScale = (irr) => padT + innerH - (irr / yMax) * innerH;
  const rScale = (upb) => 6 + Math.sqrt(upb / 1e6) * 3;

  return (
    <div className="vrb-chart" ref={ref}>
      <div className="chart-head">
        <div>
          <div className="eyebrow">Figure 02</div>
          <h3>Hold period × gross IRR</h3>
        </div>
        <div className="chart-legend">
          <span><i style={{background:"var(--vrb-blue)"}}></i>Residential</span>
          <span><i style={{background:"var(--vrb-navy)"}}></i>Multifamily</span>
          <span><i style={{background:"var(--vrb-green)"}}></i>Hospitality</span>
          <span className="legend-sep">·</span>
          <span style={{opacity:0.7}}>circle size = UPB</span>
        </div>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} className="chart-svg" role="img" aria-label="Scatter plot: hold period in months by gross IRR">
        {/* Grid */}
        {[0, 10, 20, 30, 40].map(v => {
          const y = yScale(v);
          return (
            <g key={"y"+v}>
              <line x1={padL} x2={W - padR} y1={y} y2={y}
                stroke="var(--vrb-ink-200)" strokeWidth={v === 0 ? 1.5 : 1}
                strokeDasharray={v === 0 ? "" : "2 4"} />
              <text x={padL - 10} y={y + 4} fontFamily="var(--font-mono)" fontSize="10"
                fill="var(--vrb-ink-500)" textAnchor="end">{v}%</text>
            </g>
          );
        })}
        {[0, 6, 12, 18, 24].map(v => {
          const x = xScale(v);
          return (
            <g key={"x"+v}>
              <line x1={x} x2={x} y1={padT} y2={padT + innerH}
                stroke="var(--vrb-ink-200)" strokeWidth={v === 0 ? 1.5 : 1}
                strokeDasharray={v === 0 ? "" : "2 4"} />
              <text x={x} y={padT + innerH + 18} fontFamily="var(--font-mono)" fontSize="10"
                fill="var(--vrb-ink-500)" textAnchor="middle">{v}</text>
            </g>
          );
        })}
        {/* Trend line: weighted avg IRR */}
        {(() => {
          const avgIrr = deals.reduce((s, d) => s + d.irr, 0) / deals.length;
          const y = yScale(avgIrr);
          return (
            <g>
              <line x1={padL} x2={W - padR} y1={y} y2={y}
                stroke="var(--vrb-blue)" strokeWidth="1" strokeDasharray="6 4" opacity={seen ? 0.6 : 0}
                style={{ transition: "opacity 800ms ease 1200ms" }} />
              <text x={W - padR - 6} y={y - 6} fontFamily="var(--font-mono)" fontSize="10" fontWeight="600"
                fill="var(--vrb-blue)" textAnchor="end" opacity={seen ? 1 : 0}
                style={{ transition: "opacity 800ms ease 1400ms" }}>
                AVG {avgIrr.toFixed(1)}%
              </text>
            </g>
          );
        })()}
        {/* Dots */}
        {deals.map((d, i) => {
          const x = xScale(d.hold);
          const y = yScale(d.irr);
          const r = rScale(d.upb);
          return (
            <g key={d.id} opacity={seen ? 1 : 0}
              style={{ transition: `opacity 700ms ease ${i * 90}ms, transform 700ms cubic-bezier(.2,.8,.2,1) ${i * 90}ms`, transform: seen ? "scale(1)" : "scale(0)", transformOrigin: `${x}px ${y}px` }}>
              <circle cx={x} cy={y} r={r} fill={colorByType[d.type]} fillOpacity="0.18" stroke={colorByType[d.type]} strokeWidth="1.6" />
              <circle cx={x} cy={y} r={2.5} fill={colorByType[d.type]} />
            </g>
          );
        })}
        {/* Axes labels */}
        <text x={padL + innerW / 2} y={H - 14} fontFamily="var(--font-mono)" fontSize="10" fontWeight="600"
          fill="var(--vrb-ink-500)" textAnchor="middle" letterSpacing="0.08em">HOLD PERIOD (MONTHS)</text>
        <text x={16} y={padT - 8}
          fontFamily="var(--font-mono)" fontSize="10" fontWeight="600"
          fill="var(--vrb-ink-500)" letterSpacing="0.08em">GROSS IRR (%)</text>
      </svg>
      <p className="chart-caption">
        Each dot represents one resolved transaction. Larger circles indicate larger UPB. The dashed reference line marks the resolved-portfolio weighted average gross IRR. Residential deals cluster shorter and higher; hospitality deals carry longer holds with deeper basis.
      </p>
    </div>
  );
};

// ============ US DOT MAP ============
// Latitude/longitude reference grid + city dots. No US silhouette — editorial-style.
window.USDotMap = function USDotMap() {
  const [ref, seen] = useInView(0.2);
  const deals = window.TrackRecord;
  const geo = window.VRB_CITY_GEO;

  // viewBox: 1000 x 500
  // Lon range: -125 to -65 (60 deg) -> x: 60 to 940
  // Lat range: 24 to 50 (26 deg) -> y: 440 to 60 (inverted)
  const project = ([lat, lon]) => {
    const x = 60 + ((lon - -125) / 60) * 880;
    const y = 60 + ((50 - lat) / 26) * 380;
    return [x, y];
  };

  // Group deals by city, accumulate UPB
  const byCity = {};
  deals.forEach(d => {
    if (!byCity[d.loc]) byCity[d.loc] = { count: 0, upb: 0, deals: [] };
    byCity[d.loc].count++;
    byCity[d.loc].upb += d.upb;
    byCity[d.loc].deals.push(d);
  });

  return (
    <div className="vrb-chart" ref={ref}>
      <div className="chart-head">
        <div>
          <div className="eyebrow">Figure 03</div>
          <h3>Geographic distribution · 12 transactions</h3>
        </div>
        <div className="chart-legend">
          <span><i style={{background:"var(--vrb-blue)"}}></i>Active sourcing</span>
          <span className="legend-sep">·</span>
          <span style={{opacity:0.7}}>circle size = total UPB</span>
        </div>
      </div>
      <svg viewBox="0 0 1000 500" className="chart-svg chart-svg-map" role="img" aria-label="US map of VRB Capital transactions">
        {/* Latitude lines */}
        {[28, 32, 36, 40, 44, 48].map(lat => {
          const [, y] = project([lat, -95]);
          return (
            <g key={"lat"+lat}>
              <line x1={60} x2={940} y1={y} y2={y}
                stroke="var(--vrb-ink-200)" strokeWidth="1" strokeDasharray="2 4" />
              <text x={50} y={y + 4} fontFamily="var(--font-mono)" fontSize="9"
                fill="var(--vrb-ink-400)" textAnchor="end">{lat}°N</text>
            </g>
          );
        })}
        {/* Longitude lines */}
        {[-120, -110, -100, -90, -80, -70].map(lon => {
          const [x] = project([35, lon]);
          return (
            <g key={"lon"+lon}>
              <line x1={x} x2={x} y1={60} y2={440}
                stroke="var(--vrb-ink-200)" strokeWidth="1" strokeDasharray="2 4" />
              <text x={x} y={455} fontFamily="var(--font-mono)" fontSize="9"
                fill="var(--vrb-ink-400)" textAnchor="middle">{Math.abs(lon)}°W</text>
            </g>
          );
        })}
        {/* Frame */}
        <rect x={60} y={60} width={880} height={380} fill="none" stroke="var(--vrb-ink-300)" strokeWidth="1.25" />
        {/* "Sunbelt corridor" annotation band */}
        <rect x={60} y={project([34, 0])[1]} width={880} height={project([28, 0])[1] - project([34, 0])[1]}
          fill="var(--vrb-blue)" opacity={seen ? 0.05 : 0}
          style={{ transition: "opacity 1000ms ease 600ms" }} />
        <text x={70} y={project([29, 0])[1] - 4} fontFamily="var(--font-mono)" fontSize="9"
          fill="var(--vrb-blue)" letterSpacing="0.12em" fontWeight="600"
          opacity={seen ? 0.7 : 0}
          style={{ transition: "opacity 1000ms ease 800ms" }}>
          SUNBELT CORRIDOR
        </text>

        {/* Connecting lines from HQ (Itasca, IL ~ 41.97, -88.04) to each deal */}
        {(() => {
          const [hx, hy] = project([41.97, -88.04]);
          return Object.entries(byCity).map(([loc, g], i) => {
            if (!geo[loc]) return null;
            const [x, y] = project(geo[loc]);
            const len = Math.hypot(x - hx, y - hy);
            return (
              <line key={"ln"+loc} x1={hx} y1={hy} x2={x} y2={y}
                stroke="var(--vrb-blue)" strokeWidth="0.75" strokeDasharray={`${len} ${len}`}
                strokeDashoffset={seen ? 0 : len} opacity={0.35}
                style={{ transition: `stroke-dashoffset 1400ms cubic-bezier(.2,.8,.2,1) ${400 + i * 60}ms` }} />
            );
          });
        })()}

        {/* HQ marker */}
        {(() => {
          const [hx, hy] = project([41.97, -88.04]);
          return (
            <g opacity={seen ? 1 : 0} style={{ transition: "opacity 600ms ease 200ms" }}>
              <circle cx={hx} cy={hy} r={14} fill="none" stroke="var(--vrb-navy)" strokeWidth="1" opacity="0.4">
                <animate attributeName="r" values="8;18;8" dur="2.4s" repeatCount="indefinite" />
                <animate attributeName="opacity" values="0.6;0;0.6" dur="2.4s" repeatCount="indefinite" />
              </circle>
              <circle cx={hx} cy={hy} r={5} fill="var(--vrb-navy)" />
              <text x={hx + 10} y={hy - 8} fontFamily="var(--font-mono)" fontSize="10" fontWeight="700"
                fill="var(--vrb-navy)" letterSpacing="0.08em">HQ · ITASCA, IL</text>
            </g>
          );
        })()}

        {/* City dots */}
        {Object.entries(byCity).map(([loc, g], i) => {
          if (!geo[loc]) return null;
          const [x, y] = project(geo[loc]);
          const r = 5 + Math.sqrt(g.upb / 1e6) * 1.4;
          return (
            <g key={loc} opacity={seen ? 1 : 0}
              style={{ transition: `opacity 600ms ease ${800 + i * 80}ms` }}>
              <circle cx={x} cy={y} r={r + 4} fill="var(--vrb-blue)" opacity="0.15" />
              <circle cx={x} cy={y} r={r} fill="var(--vrb-blue)" />
              <circle cx={x} cy={y} r={r + 8} fill="none" stroke="var(--vrb-blue)" strokeWidth="0.75" opacity="0.4">
                <animate attributeName="r" values={`${r};${r+12};${r}`} dur="3s" repeatCount="indefinite" begin={`${i*0.25}s`} />
                <animate attributeName="opacity" values="0.5;0;0.5" dur="3s" repeatCount="indefinite" begin={`${i*0.25}s`} />
              </circle>
              <text x={x + r + 6} y={y - 4}
                fontFamily="var(--font-mono)" fontSize="10" fontWeight="600"
                fill="var(--vrb-navy)">{loc.split(",")[0]}</text>
              <text x={x + r + 6} y={y + 8}
                fontFamily="var(--font-mono)" fontSize="9"
                fill="var(--vrb-ink-500)">${(g.upb / 1e6).toFixed(1)}M · {g.count} {g.count === 1 ? "deal" : "deals"}</text>
            </g>
          );
        })}
      </svg>
      <p className="chart-caption">
        VRB Capital sources nationally with concentration in the Sunbelt and Midwest. {Object.keys(byCity).length} cities across {new Set(Object.keys(byCity).map(c => c.split(",")[1].trim())).size} states. The corridor between latitudes 28°N–34°N — where job growth, in‑migration, and non‑judicial foreclosure regimes converge — represents the largest share of resolved transactions.
      </p>
    </div>
  );
};

Object.assign(window, {
  VintageWaterfall: window.VintageWaterfall,
  HoldIrrScatter: window.HoldIrrScatter,
  USDotMap: window.USDotMap,
  VRB_CITY_GEO: window.VRB_CITY_GEO
});
