import {
  LineChart,
  Line,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ReferenceLine,
  ReferenceArea,
  ResponsiveContainer,
  Legend,
} from 'recharts';
import type { CurvePoint } from '../../api/types';

interface Props {
  curve: CurvePoint[];
  dusk: string;
  dawn: string;
  trueDarkStart?: string;
  trueDarkEnd?: string;
  meridianFlip?: string;
  transitUtc?: string;
  horizonPoints?: { az_deg: number; alt_deg: number }[];
  moonSepDeg?: number;
}

function fmtHour(utc: string): string {
  return new Date(utc).toLocaleTimeString('fr-FR', {
    hour: '2-digit',
    minute: '2-digit',
    timeZone: 'Europe/Paris',
  });
}

/** Interpolate horizon alt at a given azimuth — mirrors backend horizon_alt() exactly. */
function horizonAlt(az: number, pts: { az_deg: number; alt_deg: number }[]): number {
  if (!pts.length) return 15;
  const norm = ((az % 360) + 360) % 360;
  const loIdx = Math.floor(norm) % 360;
  const hiIdx = (loIdx + 1) % 360;
  const frac = norm - Math.floor(norm);
  const loAlt = pts.find(p => p.az_deg === loIdx)?.alt_deg ?? 15;
  const hiAlt = pts.find(p => p.az_deg === hiIdx)?.alt_deg ?? 15;
  return loAlt + frac * (hiAlt - loAlt);
}

export default function AltitudeCurve({
  curve,
  dusk,
  dawn,
  trueDarkStart,
  trueDarkEnd,
  meridianFlip,
  horizonPoints,
  moonSepDeg,
}: Props) {
  if (!curve || curve.length === 0) {
    return (
      <div style={{ color: 'var(--text-lo)', fontFamily: 'var(--font-mono)', fontSize: 12, padding: 16 }}>
        No visibility curve available.
      </div>
    );
  }

  // Subsample to ~120 points max for rendering performance (1-min data = 480+ points)
  const stride = Math.max(1, Math.floor(curve.length / 120));
  const sampled = curve.filter((_, i) => i % stride === 0);

  const data = sampled
    .filter(p => p.alt_deg > 0) // Only show above 0° altitude
    .map(p => {
      const horizonAltitude = horizonPoints?.length
        ? horizonAlt(p.az_deg, horizonPoints)
        : 15;
      const belowHorizon = p.alt_deg < horizonAltitude;
      return {
        time: p.utc,
        alt: belowHorizon ? null : Math.round(p.alt_deg * 10) / 10,
        altBelowHorizon: belowHorizon ? Math.round(p.alt_deg * 10) / 10 : null,
        // Only draw moon curve when above horizon
        moon: p.moon_alt_deg > 0 ? Math.round(p.moon_alt_deg * 10) / 10 : null,
        az: p.az_deg,
        label: fmtHour(p.utc),
        horizon: Math.round(horizonAltitude * 10) / 10,
        belowHorizon, // Flag for styling
      };
    });

  // Find contiguous windows where moon is above horizon — shade those periods in blue-warn
  // Also shade with a stronger tint if moonSepDeg < 30° (close approach)
  type MoonWindow = { x1: string; x2: string; close: boolean };
  const moonWindows: MoonWindow[] = [];
  let winStart: { label: string; close: boolean } | null = null;
  for (let i = 0; i < data.length; i++) {
    const pt = data[i];
    const moonUp = (pt.moon ?? 0) > 0;
    const close = moonSepDeg != null && moonSepDeg < 30 && moonUp;
    if (moonUp && !winStart) {
      winStart = { label: pt.label, close };
    } else if (!moonUp && winStart) {
      moonWindows.push({ x1: winStart.label, x2: data[i - 1].label, close: winStart.close });
      winStart = null;
    }
  }
  if (winStart && data.length > 0) {
    moonWindows.push({ x1: winStart.label, x2: data[data.length - 1].label, close: winStart.close });
  }

  const nowUtc = new Date().toISOString();

  return (
    <div style={{ width: '100%', height: 240 }}>
      <ResponsiveContainer>
        <LineChart data={data} margin={{ top: 4, right: 8, bottom: 4, left: -10 }}>
          <CartesianGrid stroke="var(--border)" strokeDasharray="3 3" vertical={false} />
          <XAxis
            dataKey="label"
            tick={{ fill: 'var(--text-lo)', fontSize: 10, fontFamily: 'IBM Plex Mono' }}
            interval="preserveStartEnd"
            tickLine={false}
          />
          <YAxis
            domain={[0, 90]}
            tick={{ fill: 'var(--text-lo)', fontSize: 10, fontFamily: 'IBM Plex Mono' }}
            tickLine={false}
            tickFormatter={v => `${v}°`}
          />
          <Tooltip
            contentStyle={{
              background: 'var(--bg-panel)',
              border: '1px solid var(--border-hi)',
              borderRadius: 4,
              fontFamily: 'IBM Plex Mono',
              fontSize: 11,
              color: 'var(--text-hi)',
            }}
            formatter={(value: number, name: string) => {
              if (name === 'horizon') return [`${value}°`, 'Horizon'];
              if (name === 'moon') return [`${value}°`, 'Moon'];
              if (name === 'altBelowHorizon') return [`${value}°`, 'Altitude (below horizon)'];
              return [`${value}°`, 'Altitude'];
            }}
            labelStyle={{ color: 'var(--text-mid)' }}
          />

          {/* True dark window shading */}
          {trueDarkStart && trueDarkEnd && (
            <ReferenceArea
              x1={fmtHour(trueDarkStart)}
              x2={fmtHour(trueDarkEnd)}
              fill="var(--amber-glow)"
              strokeOpacity={0}
            />
          )}

          {/* Moon-above-horizon shading — subtle blue tint; stronger orange if within 30° */}
          {moonWindows.map((w, i) => (
            <ReferenceArea
              key={i}
              x1={w.x1}
              x2={w.x2}
              fill={w.close ? 'rgba(232,131,42,0.10)' : 'rgba(77,157,224,0.08)'}
              strokeOpacity={0}
            />
          ))}

          {/* 15° line */}
          <ReferenceLine y={15} stroke="var(--muted)" strokeDasharray="4 4" />
          {/* 30° line */}
          <ReferenceLine y={30} stroke="var(--good)" strokeDasharray="4 4" strokeOpacity={0.4} />

          {/* Meridian flip */}
          {meridianFlip && (
            <ReferenceLine
              x={fmtHour(meridianFlip)}
              stroke="var(--amber)"
              strokeDasharray="6 3"
              label={{ value: 'Flip', fill: 'var(--amber)', fontSize: 9, fontFamily: 'IBM Plex Mono' }}
            />
          )}

          {/* Now marker */}
          {nowUtc >= dusk && nowUtc <= dawn && (
            <ReferenceLine
              x={fmtHour(nowUtc)}
              stroke="var(--amber)"
              strokeWidth={2}
            />
          )}

          {/* Moon altitude curve — dimmed blue */}
          <Line
            type="monotone"
            dataKey="moon"
            stroke="#4d9de0"
            strokeWidth={1}
            dot={false}
            activeDot={false}
            strokeOpacity={0.5}
            strokeDasharray="4 2"
          />

          {/* Altitude below custom horizon — greyed out */}
          <Line
            type="monotone"
            dataKey="altBelowHorizon"
            stroke="var(--good)"
            strokeWidth={2}
            dot={false}
            activeDot={false}
            strokeOpacity={0.5}
          />

          {/* Custom horizon step-line — red dashed */}
          {horizonPoints && horizonPoints.length > 0 && (
            <Line
              type="stepAfter"
              dataKey="horizon"
              stroke="var(--danger)"
              strokeWidth={1.5}
              strokeDasharray="3 3"
              dot={false}
              activeDot={false}
              strokeOpacity={0.7}
            />
          )}

          {/* Object altitude curve */}
          <Line
            type="monotone"
            dataKey="alt"
            stroke="var(--good)"
            strokeWidth={2}
            dot={false}
            activeDot={{ r: 4, fill: 'var(--amber)' }}
          />
        </LineChart>
      </ResponsiveContainer>
    </div>
  );
}
