// Zodiac Wheel — correct astronomical rendering per chart-brief
// Key rules (handoff §9):
//   • Ascendant (AC) anchored at 9 o'clock (SVG angle 180°)
//   • Signs and houses increase counter-clockwise (CCW)
//   • Use absLon for positioning, NOT arbitrary degrees
//   • Placidus houses are unequal — use houseCusps from data
//   • pt(lon, r): SVG angle = 180 - (lon - ascLon), in degrees → radians
//
// Field names match production normalized shape (handoff §7):
//   planet:    { name, sign, signAbbr, house, deg, absLon, retro }
//   houseCusp: { house, sign, signAbbr, deg, absLon }

// ─── Sign data ─────────────────────────────────────────────────────────────
// Append U+FE0E (variation selector-15) to force text presentation —
// otherwise macOS/iOS render these as purple emoji.
const SIGN_GLYPHS = ['♈\uFE0E','♉\uFE0E','♊\uFE0E','♋\uFE0E','♌\uFE0E','♍\uFE0E','♎\uFE0E','♏\uFE0E','♐\uFE0E','♑\uFE0E','♒\uFE0E','♓\uFE0E'];

// Sign order around the wheel (0° Aries → 330° Pisces). Indices match
// SIGN_GLYPHS. Used to look up element/colour from lookups.jsx.
const SIGN_ORDER = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces'];
const SIGN_ELEMENTS = SIGN_ORDER.map(s => (window.SIGN_ELEM || {})[s] || 'fire');

// Translucent element backgrounds for sign sectors (derived from ELEM_COLOR)
const _hexToRgba = (hex, alpha) => {
  const n = parseInt(hex.slice(1), 16);
  return `rgba(${(n>>16)&255},${(n>>8)&255},${n&255},${alpha})`;
};
const _EC = window.ELEM_COLOR || { fire:'#a32d2d', earth:'#3b6d11', air:'#0c447c', water:'#3c3489' };
const ELEMENT_BG = {
  fire:  _hexToRgba(_EC.fire,  0.10),
  earth: _hexToRgba(_EC.earth, 0.10),
  air:   _hexToRgba(_EC.air,   0.12),
  water: _hexToRgba(_EC.water, 0.12),
};
// Legacy alias used elsewhere in the codebase
const ELEMENT_COLORS = _EC;

// Theme palettes — colors used outside the sign sectors (rings, labels, fills)
const themes = {
  dusk:    { bg:'#0D1B2E', line:'#8B93D4', glyph:'#E8F0FF', center:'#0D1B2E', label:'#8A9BB0', accent:'#5B63B7' },
  duskAlt: { bg:'#0D1B2E', line:'#5B63B7', glyph:'#8B93D4', center:'#0D1B2E', label:'#8A9BB0', accent:'#8B93D4' },
  light:   { bg:'#FAFBFD', line:'#5B63B7', glyph:'#0D1B2E', center:'#FAFBFD', label:'#5B6378', accent:'#5B63B7' },
};

// ─── Wheel component ───────────────────────────────────────────────────────
// Props:
//   size      — SVG box dimension
//   data      — { planets, houseCusps, ascLon } in production normalized shape
//   theme     — 'dusk' | 'duskAlt' | 'light'
//   animate   — render with stroke-drawing animation
//   progress  — 0..1 (for loading state; 1 = fully drawn)
//   showLabels— show planet degree/sign labels
function ChartWheel({ size = 320, data = SAMPLE_WHEEL_DATA, theme = 'dusk', animate = false, progress = 1, showLabels = true }){
  const palette = themes[theme] || themes.dusk;
  const cx = 150, cy = 150;
  const rO = 144, rS = 124, rH = 98, rP = 76, rI = 40;

  const ascLon = data.ascLon
    ?? data.planets?.find(p => p.name === 'Ascendant')?.absLon
    ?? 0;

  // Convert ecliptic longitude → SVG point at radius r
  // SVG angle (degrees) = 180 - (lon - ascLon), so AC at lon=ascLon lands at SVG 180° (left = 9 o'clock).
  const pt = (lon, r) => {
    const a = (180 - (lon - ascLon)) * Math.PI / 180;
    return { x: cx + r * Math.cos(a), y: cy + r * Math.sin(a) };
  };

  // Build a sign-sector path: outer arc CCW (sweep=0), inner arc back (sweep=1)
  const signSectorPath = (lon0, lon1) => {
    const p1 = pt(lon0, rS), p2 = pt(lon0, rO);
    const p3 = pt(lon1, rO), p4 = pt(lon1, rS);
    return `M${p1.x},${p1.y}L${p2.x},${p2.y}A${rO},${rO} 0 0,0 ${p3.x},${p3.y}L${p4.x},${p4.y}A${rS},${rS} 0 0,1 ${p1.x},${p1.y}Z`;
  };

  const houseCusps = data.houseCusps || data.house_cusps || [];
  const planets    = (data.planets || [])
    .filter(p => p.name !== 'Medium_Coeli' && p.name !== 'MC');

  const totalCirc = 2 * Math.PI * rO;

  return (
    <svg width={size} height={size} viewBox="0 0 300 300" style={{display:'block'}}>
      <defs>
        <radialGradient id={`wheel-center-${theme}`} cx="50%" cy="50%" r="50%">
          <stop offset="0%"  stopColor={palette.accent} stopOpacity="0.18"/>
          <stop offset="100%" stopColor={palette.accent} stopOpacity="0"/>
        </radialGradient>
      </defs>

      {/* Layer 0 — soft center glow */}
      <circle cx={cx} cy={cy} r={rH} fill={`url(#wheel-center-${theme})`} opacity={progress}/>

      {/* Layer 1 — sign sectors (12 equal 30° slices) */}
      {Array.from({length:12}).map((_,i)=>{
        const lon0 = i*30, lon1 = (i+1)*30;
        const elem = SIGN_ELEMENTS[i];
        return (
          <path key={`sect-${i}`} d={signSectorPath(lon0, lon1)}
                fill={ELEMENT_BG[elem]} stroke="none"
                opacity={progress > 0.05 ? 1 : 0}
                style={{transition: animate ? 'opacity .4s' : 'none'}}/>
        );
      })}

      {/* Outer + inner sign-ring boundaries */}
      <circle cx={cx} cy={cy} r={rO} fill="none" stroke={palette.line} strokeWidth="0.8"
              strokeDasharray={totalCirc}
              strokeDashoffset={totalCirc * (1 - progress)}
              style={{transition: animate ? 'stroke-dashoffset 1.4s ease-out' : 'none', opacity:0.7}}/>
      <circle cx={cx} cy={cy} r={rS} fill="none" stroke={palette.line} strokeWidth="0.4" opacity="0.5"/>

      {/* Sign division lines (12 spokes from rS to rO) */}
      {Array.from({length:12}).map((_,i)=>{
        const lon = i*30;
        const a = pt(lon, rS), b = pt(lon, rO);
        return (
          <line key={`spoke-${i}`} x1={a.x} y1={a.y} x2={b.x} y2={b.y}
                stroke={palette.line} strokeWidth="0.5" opacity={progress > 0.2 ? 0.6 : 0}
                style={{transition: animate ? `opacity .25s ${0.2 + i*0.03}s` : 'none'}}/>
        );
      })}

      {/* Sign glyphs */}
      {SIGN_GLYPHS.map((g,i)=>{
        const midLon = i*30 + 15;
        const p = pt(midLon, (rO+rS)/2);
        const elem = SIGN_ELEMENTS[i];
        const visible = progress > 0.3 + i*0.02;
        return (
          <text key={`glyph-${i}`} x={p.x} y={p.y} textAnchor="middle" dominantBaseline="central"
                fontSize={11.5} fontFamily='"Noto Serif TC", serif'
                fill={palette.glyph}
                opacity={visible ? 0.95 : 0}
                style={{transition: animate ? `opacity .3s ${0.3 + i*0.04}s` : 'none',
                        fontVariantEmoji:'text'}}>
            {g}
          </text>
        );
      })}

      {/* Layer 2 — House cusp lines (unequal Placidus) */}
      {houseCusps.length === 12 && houseCusps.map((c, i) => {
        const isAngular = c.house === 1 || c.house === 4 || c.house === 7 || c.house === 10;
        const inner = pt(c.absLon, rI);
        const outer = pt(c.absLon, rH);
        const visible = progress > 0.5;
        return (
          <g key={`cusp-${c.house}`} opacity={visible ? 1 : 0}
             style={{transition: animate ? `opacity .3s ${0.55 + i*0.04}s` : 'none'}}>
            <line x1={inner.x} y1={inner.y} x2={outer.x} y2={outer.y}
                  stroke={palette.line}
                  strokeWidth={isAngular ? 1.0 : 0.45}
                  opacity={isAngular ? 0.85 : 0.4}/>
          </g>
        );
      })}

      {/* House numbers, at midpoint between consecutive cusps */}
      {houseCusps.length === 12 && houseCusps.map((c, i) => {
        const next = houseCusps[(i+1) % 12];
        let lon0 = c.absLon;
        let lon1 = next.absLon;
        // Account for wraparound: ensure lon1 > lon0 going CCW
        if (lon1 < lon0) lon1 += 360;
        const mid = (lon0 + lon1) / 2;
        const p = pt(mid, (rH + rI) / 2 + 8);
        const visible = progress > 0.55;
        return (
          <text key={`hnum-${c.house}`} x={p.x} y={p.y} textAnchor="middle" dominantBaseline="central"
                fontSize={8.5} fontFamily="Inter, sans-serif" letterSpacing="0.04em"
                fill={palette.label} opacity={visible ? 0.7 : 0}
                style={{transition: animate ? 'opacity .3s .7s' : 'none', fontWeight:500}}>
            {c.house}
          </text>
        );
      })}

      {/* Outer ring boundary (already drawn). Inner disc cover. */}
      <circle cx={cx} cy={cy} r={rI} fill={palette.center}/>
      <circle cx={cx} cy={cy} r={rI} fill="none" stroke={palette.line} strokeWidth="0.4" opacity="0.4"/>

      {/* AC marker — a small AC label just inside the outer ring at 9 o'clock */}
      <g opacity={progress > 0.4 ? 1 : 0}
         style={{transition: animate ? 'opacity .3s .5s' : 'none'}}>
        <text x={pt(ascLon, rO + 9).x} y={pt(ascLon, rO + 9).y}
              textAnchor="middle" dominantBaseline="central"
              fontSize={8.5} letterSpacing="0.18em"
              fontFamily="Inter, sans-serif" fill={palette.accent} fontWeight={700}>
          AC
        </text>
      </g>

      {/* Layer 3 — Planet glyphs at rP */}
      {planets.map((p, i) => {
        const glyph = (window.PLANET_GLYPH || {})[p.name] || '?';
        const color = (window.PLANET_COLOR || {})[p.name] || palette.glyph;
        const pos = pt(p.absLon, rP);
        const labelPos = pt(p.absLon, rP - 14);
        const visible = progress > 0.65 + i*0.025;
        const delay = 0.7 + i * 0.06;
        const isAC = p.name === 'Ascendant';
        if (isAC) return null; // AC already labelled outside
        return (
          <g key={`pl-${i}`} opacity={visible ? 1 : 0}
             style={{transition: animate ? `opacity .35s ${delay}s` : 'none'}}>
            <circle cx={pos.x} cy={pos.y} r={9}
                    fill={palette.center} stroke={color} strokeWidth="0.9"/>
            <text x={pos.x} y={pos.y + 0.5} textAnchor="middle" dominantBaseline="central"
                  fontSize={10} fontFamily="var(--font-zh, 'Noto Serif TC', serif)" fill={color}>
              {glyph}
            </text>
            {showLabels && (
              <text x={labelPos.x} y={labelPos.y} textAnchor="middle" dominantBaseline="central"
                    fontSize={6.5} fontFamily='"JetBrains Mono", monospace'
                    fill={palette.label} opacity={0.65} letterSpacing="0.04em">
                {Math.floor(p.deg)}°{p.retro ? '℞' : ''}
              </text>
            )}
            {/* retrograde dot indicator */}
            {p.retro && (
              <circle cx={pos.x + 6.5} cy={pos.y - 6.5} r={1.4} fill={color}/>
            )}
          </g>
        );
      })}

      {/* Center dot */}
      <circle cx={cx} cy={cy} r={1.5} fill={palette.glyph} opacity={progress}/>
    </svg>
  );
}

// ─── Backwards-compatible alias names used by existing code ────────────────
// Old code calls TraditionalWheel / MinimalistWheel — we keep both as thin wrappers.
function TraditionalWheel({ size = 260, theme = 'dusk', animate = true, progress = 1, data = SAMPLE_WHEEL_DATA }) {
  return <ChartWheel size={size} theme={theme} animate={animate} progress={progress} data={data} showLabels={true}/>;
}
function MinimalistWheel({ size = 260, theme = 'dusk', animate = true, progress = 1, data = SAMPLE_WHEEL_DATA }) {
  // Same astronomical logic; just suppress labels for a cleaner look
  return <ChartWheel size={size} theme={theme === 'dusk' ? 'duskAlt' : theme} animate={animate} progress={progress} data={data} showLabels={false}/>;
}

Object.assign(window, {
  ChartWheel, TraditionalWheel, MinimalistWheel,
  SIGN_GLYPHS, SIGN_ORDER, SIGN_ELEMENTS, ELEMENT_COLORS, themes,
});
