import { useCallback, useEffect, useMemo, useRef, useState } from "react";

import { getScene, type InjectedFlight, type Scene, type SceneFlight } from "../api";
import RadarScope, { type ActiveAlert } from "../components/RadarScope";
import { classify } from "../components/classify";
import { useT } from "../i18n";

const SPEEDS = [1, 10, 30, 60];
const AIRLINES = ["IBE", "AEA", "RYR", "VLG", "AFR", "BAW", "DLH", "KLM", "EZY", "UAE", "QTR", "AAL"];
const MOBILE_BREAKPOINT = 900;
const MOBILE_ALERT_LIMIT = 3;

function newCallsign(seed: number): string {
  const airline = AIRLINES[seed % AIRLINES.length];
  const number = 100 + (seed * 37) % 8900;
  return `${airline}${number}`;
}

function useIsMobile(): boolean {
  const [isMobile, setIsMobile] = useState(() => {
    if (typeof window === "undefined") return false;
    return window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT}px)`).matches;
  });
  useEffect(() => {
    if (typeof window === "undefined") return;
    const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT}px)`);
    const handler = (event: MediaQueryListEvent) => setIsMobile(event.matches);
    mql.addEventListener("change", handler);
    return () => mql.removeEventListener("change", handler);
  }, []);
  return isMobile;
}

interface MonitorProps {
  injected: InjectedFlight | null;
  onClearInjected: () => void;
}

export default function Monitor({ injected, onClearInjected }: MonitorProps) {
  const t = useT();
  const isMobile = useIsMobile();
  const [scene, setScene] = useState<Scene | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [simTime, setSimTime] = useState(120);
  const [speed, setSpeed] = useState(1);
  const [running, setRunning] = useState(true);
  const [selectedId, setSelectedId] = useState<number | null>(null);
  const [flights, setFlights] = useState<SceneFlight[]>([]);
  const [alerts, setAlerts] = useState<ActiveAlert[]>([]);
  const respawnSeedRef = useRef(1000);
  const handleAlerts = useCallback((next: ActiveAlert[]) => {
    setAlerts((prev) => {
      if (prev.length !== next.length) return next;
      for (let i = 0; i < prev.length; i++) {
        if (prev[i].id !== next[i].id || prev[i].classification.kind !== next[i].classification.kind) return next;
      }
      return prev;
    });
  }, []);
  const rafRef = useRef<number | null>(null);
  const lastTickRef = useRef<number>(0);

  useEffect(() => {
    getScene(25)
      .then((data) => {
        setScene(data);
        setFlights(data.flights);
        if (data.flights.length) setSelectedId(data.flights[0].id);
      })
      .catch((reason) => setError(String(reason)));
  }, []);

  useEffect(() => {
    if (!running) return;
    lastTickRef.current = performance.now();
    const step = (now: number) => {
      const dt = (now - lastTickRef.current) / 1000;
      lastTickRef.current = now;
      setSimTime((value) => value + dt * speed);
      rafRef.current = requestAnimationFrame(step);
    };
    rafRef.current = requestAnimationFrame(step);
    return () => {
      if (rafRef.current != null) cancelAnimationFrame(rafRef.current);
    };
  }, [running, speed]);

  useEffect(() => {
    if (!flights.length) return;
    const updated = flights.map((flight) => {
      const endT = flight.start_offset + flight.path[flight.path.length - 1].t;
      if (simTime <= endT + 5) return flight;
      const delay = 30 + Math.random() * 60;
      const seed = respawnSeedRef.current++;
      return {
        ...flight,
        start_offset: simTime + delay,
        callsign: newCallsign(seed),
      };
    });
    if (updated.some((flight, i) => flight !== flights[i])) {
      setFlights(updated);
    }
  }, [simTime, flights]);

  const [injectedFlight, setInjectedFlight] = useState<SceneFlight | null>(null);
  const audioPlayedRef = useRef<number | null>(null);
  useEffect(() => {
    if (injected) {
      setInjectedFlight({ ...injected, start_offset: simTime + 5 });
      audioPlayedRef.current = null;
    } else {
      setInjectedFlight(null);
    }
  }, [injected]);

  useEffect(() => {
    if (!injectedFlight) return;
    if (audioPlayedRef.current === injectedFlight.id) return;
    const localT = simTime - injectedFlight.start_offset;
    if (localT < 0) return;
    audioPlayedRef.current = injectedFlight.id;
    const sequence = ["/atc/tower1.mp3", "/atc/plane.mp3", "/atc/tower2.mp3"];
    let idx = 0;
    const playNext = () => {
      if (idx >= sequence.length) return;
      const audio = new Audio(sequence[idx]);
      audio.volume = 0.85;
      audio.addEventListener("ended", () => {
        idx++;
        setTimeout(playNext, 600);
      });
      audio.play().catch(() => {});
    };
    playNext();
  }, [simTime, injectedFlight]);

  useEffect(() => {
    if (!injectedFlight) return;
    const endT = injectedFlight.start_offset + injectedFlight.path[injectedFlight.path.length - 1].t;
    if (simTime > endT + 10) {
      setInjectedFlight(null);
      onClearInjected();
    }
  }, [simTime, injectedFlight, onClearInjected]);

  const allFlights = useMemo(
    () => (injectedFlight ? [...flights, injectedFlight] : flights),
    [flights, injectedFlight],
  );

  const stepThreshold = scene?.step_threshold ?? 0;
  const stepSeconds = scene?.step_seconds ?? 10;
  const center = useMemo(() => scene?.center ?? { lat: 40.4936, lon: -3.5668 }, [scene]);

  if (error) {
    return <div className="status-alert">{t.monitor.offline}</div>;
  }
  if (!scene) {
    return <div className="label">LOADING SCENE...</div>;
  }

  const activeIds = new Set(
    allFlights
      .filter((flight) => {
        const localT = simTime - flight.start_offset;
        return localT >= 0 && localT <= flight.path[flight.path.length - 1].t;
      })
      .map((flight) => flight.id),
  );

  const selected = allFlights.find((flight) => flight.id === selectedId);

  const minutes = Math.floor(simTime / 60);
  const seconds = Math.floor(simTime % 60);
  const clock = `T+${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;

  return (
    <div className="monitor-layout">
      <div style={{ position: "relative", borderRight: "1px solid var(--panel-edge)", minHeight: 0 }}>
        <RadarScope
          flights={allFlights}
          stepThreshold={stepThreshold}
          stepSeconds={stepSeconds}
          simTime={simTime}
          selectedId={selectedId}
          onSelect={setSelectedId}
          center={center}
          onAlerts={handleAlerts}
        />
        {alerts.length > 0 && (
          <div
            style={{
              position: "absolute",
              top: isMobile ? "auto" : 14,
              bottom: isMobile ? 60 : "auto",
              left: 14,
              right: 14,
              maxWidth: 280,
              display: "flex",
              flexDirection: "column",
              gap: 4,
              zIndex: 5,
            }}
          >
            {(isMobile ? alerts.slice(0, MOBILE_ALERT_LIMIT) : alerts).map((alert) => (
              <div
                key={alert.id}
                onClick={() => setSelectedId(alert.id)}
                className={alert.classification.critical ? "atc-blink" : ""}
                style={{
                  cursor: "pointer",
                  background: "rgba(14, 26, 31, 0.92)",
                  border: `1px solid ${alert.classification.critical ? "var(--emergency)" : "var(--alert)"}`,
                  padding: "6px 8px",
                  fontFamily: "var(--mono)",
                  fontSize: 11,
                  letterSpacing: "0.06em",
                  textTransform: "uppercase",
                  color: alert.classification.critical ? "var(--emergency)" : "var(--alert)",
                }}
              >
                <div style={{ display: "flex", justifyContent: "space-between", gap: 8 }}>
                  <span style={{ fontWeight: 700 }}>{alert.callsign}</span>
                  <span>{alert.classification.short}</span>
                </div>
                <div style={{ marginTop: 2, color: "var(--label)", fontSize: 10 }}>
                  {alert.classification.label}
                </div>
                <div style={{ color: "var(--muted)", fontSize: 10 }}>
                  {alert.classification.reason}
                </div>
              </div>
            ))}
          </div>
        )}
        <div
          style={{
            position: "absolute",
            bottom: 12,
            left: 12,
            right: isMobile ? 12 : "auto",
            display: "flex",
            gap: 6,
            alignItems: "center",
            flexWrap: isMobile ? "nowrap" : "wrap",
            overflowX: isMobile ? "auto" : "visible",
            maxWidth: isMobile ? "calc(100% - 24px)" : "calc(100% - 24px)",
            background: "rgba(14, 26, 31, 0.85)",
            border: "1px solid var(--panel-edge)",
            padding: isMobile ? "6px 8px" : "6px 10px",
            fontSize: isMobile ? 12 : 11,
            letterSpacing: "0.08em",
            textTransform: "uppercase",
          }}
        >
          <span style={{ color: "var(--info)", flexShrink: 0 }}>{clock}</span>
          <span style={{ color: "var(--panel-edge)", flexShrink: 0 }}>|</span>
          <button
            onClick={() => setRunning((value) => !value)}
            style={{
              padding: isMobile ? "8px 12px" : "2px 8px",
              fontSize: isMobile ? 12 : undefined,
              flexShrink: 0,
            }}
          >
            {isMobile ? (running ? "P" : "▶") : running ? "PAUSE" : "PLAY"}
          </button>
          {SPEEDS.map((value) => (
            <button
              key={value}
              onClick={() => setSpeed(value)}
              style={{
                padding: isMobile ? "8px 12px" : "2px 8px",
                fontSize: isMobile ? 12 : undefined,
                flexShrink: 0,
                borderColor: speed === value ? "var(--info)" : "var(--panel-edge)",
                color: speed === value ? "var(--info)" : "var(--text)",
              }}
            >
              {value}X
            </button>
          ))}
          <button
            onClick={() => setSimTime(120)}
            style={{
              padding: isMobile ? "8px 12px" : "2px 8px",
              fontSize: isMobile ? 12 : undefined,
              flexShrink: 0,
            }}
          >
            RESET
          </button>
        </div>
        {injectedFlight && (
          <div
            style={{
              position: "absolute",
              bottom: 12,
              right: 12,
              display: "flex",
              gap: 8,
              alignItems: "center",
              background: "rgba(14, 26, 31, 0.92)",
              border: "1px solid #d96bd9",
              padding: "6px 10px",
              fontSize: 11,
              letterSpacing: "0.08em",
              textTransform: "uppercase",
              color: "#d96bd9",
            }}
          >
            <span>SIM INJECTED · {injectedFlight.callsign}</span>
            <button
              onClick={() => {
                setInjectedFlight(null);
                onClearInjected();
              }}
              style={{ padding: "2px 8px", borderColor: "#d96bd9", color: "#d96bd9" }}
            >
              CLEAR
            </button>
          </div>
        )}
      </div>

      <div className="monitor-strip-panel">
        <div
          style={{
            padding: "8px 12px",
            borderBottom: "1px solid var(--panel-edge)",
            display: "flex",
            justifyContent: "space-between",
            alignItems: "baseline",
          }}
        >
          <span className="label">FLIGHT STRIPS</span>
          <span className="label" style={{ color: "var(--info)" }}>{activeIds.size} ACTIVE</span>
        </div>
        <div style={{ overflowY: "auto", flex: 1, minHeight: 0 }}>
          {allFlights.map((flight) => {
            const localT = simTime - flight.start_offset;
            const onScope = localT >= 0 && localT <= flight.path[flight.path.length - 1].t;
            const stepIndex = Math.max(
              0,
              Math.min(flight.scores.length - 1, Math.floor(localT / stepSeconds)),
            );
            const score = onScope ? flight.scores[stepIndex] : 0;
            const alerting = onScope && score >= stepThreshold;
            const stateLabel = !onScope
              ? localT < 0
                ? "INBOUND"
                : "CLEARED"
              : alerting
                ? "ALERT"
                : "TRACK";
            const stateColor = !onScope
              ? "var(--muted)"
              : alerting
                ? "var(--alert)"
                : "var(--track-normal)";
            return (
              <div
                key={flight.id}
                className={`scope-row${flight.id === selectedId ? " scope-row--selected" : ""}`}
                style={{ gridTemplateColumns: "1fr 56px 56px", color: stateColor }}
                onClick={() => setSelectedId(flight.id)}
              >
                <span>{flight.callsign}</span>
                <span style={{ textAlign: "right", color: "var(--muted)" }}>WIN {String(flight.id).padStart(4, "0")}</span>
                <span style={{ textAlign: "right" }}>{stateLabel}</span>
              </div>
            );
          })}
        </div>
        {selected && (() => {
          const localT = simTime - selected.start_offset;
          const onScope = localT >= 0 && localT <= selected.path[selected.path.length - 1].t;
          let alt = 0;
          let speedKt = 0;
          let headingDeg = 0;
          let lat = 0;
          let lon = 0;
          let currentScore = 0;
          if (onScope) {
            const path = selected.path;
            let i = 0;
            for (; i < path.length - 1; i++) {
              if (localT >= path[i].t && localT < path[i + 1].t) break;
            }
            const a = path[i];
            const b = path[Math.min(i + 1, path.length - 1)];
            const span = b.t - a.t || 1;
            const f = (localT - a.t) / span;
            lat = a.lat + (b.lat - a.lat) * f;
            lon = a.lon + (b.lon - a.lon) * f;
            alt = a.alt + (b.alt - a.alt) * f;
            const lat1 = (a.lat * Math.PI) / 180;
            const lat2 = (b.lat * Math.PI) / 180;
            const dLon = ((b.lon - a.lon) * Math.PI) / 180;
            headingDeg = (
              (Math.atan2(
                Math.sin(dLon) * Math.cos(lat2),
                Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon),
              ) * 180) / Math.PI + 360
            ) % 360;
            const R = 6371;
            const dLatHav = ((b.lat - a.lat) * Math.PI) / 180;
            const h = Math.sin(dLatHav / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) ** 2;
            const kmStep = 2 * R * Math.asin(Math.sqrt(h));
            speedKt = (kmStep / 1.852) * (3600 / stepSeconds);
            const stepIndex = Math.max(0, Math.min(selected.scores.length - 1, Math.floor(localT / stepSeconds)));
            currentScore = selected.scores[stepIndex];
          }
          const lemdLat = (center.lat * Math.PI) / 180;
          const acLat = (lat * Math.PI) / 180;
          const dLonNm = ((lon - center.lon) * Math.PI) / 180;
          const dLatNm = ((lat - center.lat) * Math.PI) / 180;
          const hNm = Math.sin(dLatNm / 2) ** 2 + Math.cos(lemdLat) * Math.cos(acLat) * Math.sin(dLonNm / 2) ** 2;
          const distKm = onScope ? 2 * 6371 * Math.asin(Math.sqrt(hNm)) : 0;
          const distNm = distKm / 1.852;
          const peakScore = Math.max(...selected.scores);
          const altFt = Math.round((alt * 3.281) / 100) * 100;
          const fl = `FL${String(Math.round((alt * 3.281) / 1000) * 10 / 10).padStart(3, "0")}`;
          const sparkW = 240;
          const sparkH = 36;
          const maxS = Math.max(stepThreshold, ...selected.scores) * 1.1 || 1;
          const sparkPath = selected.scores
            .map((s, i) => {
              const sx = (i / (selected.scores.length - 1)) * sparkW;
              const sy = sparkH - (s / maxS) * sparkH;
              return `${i === 0 ? "M" : "L"}${sx.toFixed(1)},${sy.toFixed(1)}`;
            })
            .join(" ");
          const cursorIdx = onScope
            ? Math.max(0, Math.min(selected.scores.length - 1, Math.floor(localT / stepSeconds)))
            : -1;
          const cursorX = cursorIdx >= 0 ? (cursorIdx / (selected.scores.length - 1)) * sparkW : 0;
          const thrY = sparkH - (stepThreshold / maxS) * sparkH;
          const alerting = onScope && currentScore >= stepThreshold;
          const alertClass = alerting && cursorIdx >= 0 ? classify(selected.path, cursorIdx) : null;
          const fullTable = (
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 3 }}>
              <span style={{ color: "var(--muted)" }}>CALLSIGN</span>
              <span style={{ textAlign: "right" }}>{selected.callsign}</span>
              <span style={{ color: "var(--muted)" }}>WINDOW</span>
              <span style={{ textAlign: "right" }}>{String(selected.id).padStart(5, "0")}</span>
              <span style={{ color: "var(--muted)" }}>ALTITUDE</span>
              <span style={{ textAlign: "right" }}>{onScope ? `${fl} (${altFt} FT)` : "---"}</span>
              <span style={{ color: "var(--muted)" }}>GROUND SPD</span>
              <span style={{ textAlign: "right" }}>{onScope ? `${Math.round(speedKt)} KT` : "---"}</span>
              <span style={{ color: "var(--muted)" }}>HEADING</span>
              <span style={{ textAlign: "right" }}>{onScope ? `${String(Math.round(headingDeg)).padStart(3, "0")}°` : "---"}</span>
              <span style={{ color: "var(--muted)" }}>DIST LEMD</span>
              <span style={{ textAlign: "right" }}>{onScope ? `${distNm.toFixed(1)} NM` : "---"}</span>
              <span style={{ color: "var(--muted)" }}>SCORE (NOW)</span>
              <span style={{ textAlign: "right", color: alerting ? "var(--alert)" : "var(--text)" }}>
                {onScope ? currentScore.toFixed(3) : "---"}
              </span>
              <span style={{ color: "var(--muted)" }}>PEAK</span>
              <span style={{ textAlign: "right" }}>{peakScore.toFixed(3)}</span>
              <span style={{ color: "var(--muted)" }}>THRESHOLD</span>
              <span style={{ textAlign: "right" }}>{stepThreshold.toFixed(3)}</span>
              {alertClass && (
                <>
                  <span style={{ color: "var(--muted)" }}>ALERT TYPE</span>
                  <span
                    style={{
                      textAlign: "right",
                      color: alertClass.critical ? "var(--emergency)" : "var(--alert)",
                    }}
                  >
                    {alertClass.short}
                  </span>
                  <span style={{ color: "var(--muted)" }}>SIGNATURE</span>
                  <span style={{ textAlign: "right", fontSize: 10 }}>{alertClass.label}</span>
                  <span style={{ color: "var(--muted)" }}>REASON</span>
                  <span style={{ textAlign: "right", fontSize: 10, color: "var(--label)" }}>
                    {alertClass.reason} (heuristic)
                  </span>
                </>
              )}
            </div>
          );
          const summaryTable = (
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 3 }}>
              <span style={{ color: "var(--muted)" }}>CALLSIGN</span>
              <span style={{ textAlign: "right" }}>{selected.callsign}</span>
              <span style={{ color: "var(--muted)" }}>ALTITUDE</span>
              <span style={{ textAlign: "right" }}>{onScope ? `${fl} (${altFt} FT)` : "---"}</span>
              <span style={{ color: "var(--muted)" }}>SPEED</span>
              <span style={{ textAlign: "right" }}>{onScope ? `${Math.round(speedKt)} KT` : "---"}</span>
              <span style={{ color: "var(--muted)" }}>SCORE</span>
              <span style={{ textAlign: "right", color: alerting ? "var(--alert)" : "var(--text)" }}>
                {onScope ? currentScore.toFixed(3) : "---"}
              </span>
            </div>
          );
          return (
            <div style={{ padding: "10px 12px", borderTop: "1px solid var(--panel-edge)", fontSize: 11 }}>
              <div className="label" style={{ marginBottom: 8, display: "flex", justifyContent: "space-between" }}>
                <span>SELECTED</span>
                <span style={{ color: alerting ? "var(--alert)" : onScope ? "var(--info)" : "var(--muted)" }}>
                  {onScope ? (alerting ? "ALERT" : "TRACK") : localT < 0 ? "INBOUND" : "CLEARED"}
                </span>
              </div>
              {isMobile ? (
                <>
                  {summaryTable}
                  <details style={{ marginTop: 8 }}>
                    <summary
                      className="label"
                      style={{ cursor: "pointer", color: "var(--info)", padding: "4px 0" }}
                    >
                      DETAILS
                    </summary>
                    <div style={{ marginTop: 6 }}>{fullTable}</div>
                  </details>
                </>
              ) : (
                <>
                  {fullTable}
                  <div className="label" style={{ marginTop: 10, marginBottom: 4 }}>SCORE / 10 MIN</div>
                  <svg
                    viewBox={`0 0 ${sparkW} ${sparkH}`}
                    preserveAspectRatio="none"
                    style={{ display: "block", width: "100%", height: sparkH, background: "var(--bg-deep)", border: "1px solid var(--panel-edge)" }}
                  >
                    <line x1={0} y1={thrY} x2={sparkW} y2={thrY} stroke="var(--alert)" strokeDasharray="3 3" strokeWidth={1} />
                    <path d={sparkPath} fill="none" stroke="var(--info)" strokeWidth={1.4} vectorEffect="non-scaling-stroke" />
                    {cursorIdx >= 0 && (
                      <line x1={cursorX} y1={0} x2={cursorX} y2={sparkH} stroke="var(--track-selected)" strokeWidth={1} vectorEffect="non-scaling-stroke" />
                    )}
                  </svg>
                </>
              )}
            </div>
          );
        })()}
      </div>
    </div>
  );
}
