import { useCallback, useEffect, useState } from "react";
import {
  BatteryMedium,
  ChargingStation,
  ChartLineUp,
  Database,
  Gauge,
  MapTrifold,
  RoadHorizon,
  Speedometer,
  SteeringWheel,
  Timer,
  Trash,
  Trophy,
  WarningCircle
} from "@phosphor-icons/react";
import {
  clearCarStatistics,
  getCarHistory,
  getCarStatistics,
  getCarTelemetry,
  type Availability,
  type CarStatistics,
  type CarTelemetry,
  type ClearTelemetryMode,
  type TelemetryHistoryPoint,
  type TelemetryPeriod
} from "./api";

const periods: Array<{ value: TelemetryPeriod; label: string }> = [
  { value: "24h", label: "24H" },
  { value: "7d", label: "7D" },
  { value: "30d", label: "30D" },
  { value: "1y", label: "1Y" },
  { value: "all", label: "All" }
];

export function CarPage({ csrfToken }: { csrfToken: string }) {
  const [telemetry, setTelemetry] = useState<CarTelemetry | null>(null);
  const [statistics, setStatistics] = useState<CarStatistics | null>(null);
  const [history, setHistory] = useState<TelemetryHistoryPoint[]>([]);
  const [period, setPeriod] = useState<TelemetryPeriod>("24h");
  const [error, setError] = useState("");
  const [notice, setNotice] = useState("");
  const [clearDialog, setClearDialog] = useState(false);
  const [clearing, setClearing] = useState<ClearTelemetryMode | null>(null);

  const refreshLive = useCallback(async () => {
    try {
      setTelemetry(await getCarTelemetry());
      setError("");
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : "Live car telemetry could not be loaded");
    }
  }, []);

  const refreshHistory = useCallback(async () => {
    try {
      const [nextStatistics, nextHistory] = await Promise.all([getCarStatistics(), getCarHistory(period)]);
      setStatistics(nextStatistics);
      setHistory(nextHistory.points);
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : "Car history could not be loaded");
    }
  }, [period]);

  useEffect(() => {
    void refreshLive();
    const interval = window.setInterval(() => void refreshLive(), 2_000);
    return () => window.clearInterval(interval);
  }, [refreshLive]);

  useEffect(() => {
    void refreshHistory();
    const interval = window.setInterval(() => void refreshHistory(), 15_000);
    return () => window.clearInterval(interval);
  }, [refreshHistory]);

  const speed = telemetry?.speedKph.available ? telemetry.speedKph.value : null;
  const angle = telemetry?.wheelAngleDegrees.available ? telemetry.wheelAngleDegrees.value : 0;
  const speedArc = Math.min(Math.max((speed ?? 0) / 180, 0), 1);

  const clearStatistics = async (mode: ClearTelemetryMode) => {
    setClearing(mode);
    setError("");
    setNotice("");
    try {
      await clearCarStatistics(mode, csrfToken);
      setHistory([]);
      await refreshHistory();
      setClearDialog(false);
      setNotice(mode === "all" ? "All car statistics were cleared." : "History cleared. All-time records were kept.");
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : "Car statistics could not be cleared");
    } finally {
      setClearing(null);
    }
  };

  return (
    <div className="car-page">
      {error && <div className="status-error" role="alert"><WarningCircle size={22} />{error}</div>}
      {notice && <div className="status-success" role="status">{notice}</div>}
      <section className="drive-stage">
        <div className="speed-cluster">
          <div className="speed-arc" style={{ "--speed": speedArc } as React.CSSProperties} />
          <Gauge size={28} />
          <strong>{speed === null ? "--" : Math.round(speed)}</strong>
          <span>km/h</span>
        </div>
        <div className="wheel-visual">
          <div className="wheel-angle"><SteeringWheel size={150} weight="thin" style={{ transform: `rotate(${angle}deg)` }} /></div>
          <strong>{telemetry?.wheelAngleDegrees.available ? `${telemetry.wheelAngleDegrees.value.toFixed(1)}°` : "Unavailable"}</strong>
          <span>Steering angle</span>
        </div>
        <div className="gear-cluster">
          <span>Gear signal</span>
          <strong>{telemetry?.gear.available ? telemetry.gear.value : "--"}</strong>
          <small>Raw AVM value</small>
        </div>
      </section>

      <section className="energy-readout live-energy">
        <TelemetryValue icon={<BatteryMedium size={28} />} label="Traction battery" value={telemetry?.batteryPercent} suffix="%" />
        <TelemetryValue icon={<RoadHorizon size={28} />} label="OEM range" value={telemetry?.rangeKm} suffix="km" />
        <TelemetryValue icon={<ChargingStation size={28} />} label="Battery voltage" value={telemetry?.batteryVoltage} suffix="V" decimals={1} />
        <TelemetryValue icon={<ChartLineUp size={28} />} label="Use since charge" value={telemetry?.totalConsumptionKwh} suffix="kWh" decimals={2} />
      </section>

      <section className="record-grid" aria-label="All-time vehicle statistics">
        <RecordCard icon={<Trophy size={25} />} label="Peak speed" value={formatMetric(statistics?.records.peakSpeedKph, "km/h")} note={recordedDate(statistics?.records.peakSpeedAt)} />
        <RecordCard icon={<ChargingStation size={25} />} label="Peak charge estimate" value={formatMetric(statistics?.records.peakChargingPowerKw, "kW", 1)} note="Estimated from SOC gain over time" />
        <RecordCard icon={<MapTrifold size={25} />} label="Our range estimate" value={formatMetric(statistics?.lifetime.ownRangeEstimateKm, "km")} note={statistics?.lifetime.ownRangeEstimateKm ? "Based on observed distance per SOC" : "Learning after 10 km and 5% SOC"} />
        <RecordCard icon={<RoadHorizon size={25} />} label="Best OEM range" value={formatMetric(statistics?.records.maxObservedRangeKm, "km")} note={recordedDate(statistics?.records.maxObservedRangeAt)} />
        <RecordCard icon={<Speedometer size={25} />} label="Tracked distance" value={formatMetric(statistics?.lifetime.trackedDistanceKm, "km", 1)} note={`${formatMetric(statistics?.lifetime.averageMovingSpeedKph, "km/h")} moving average`} />
        <RecordCard icon={<Timer size={25} />} label="Observed drive time" value={formatDuration(statistics?.lifetime.drivingSeconds ?? 0)} note={`${statistics?.lifetime.chargeSessions ?? 0} charging sessions detected`} />
      </section>

      <section className="history-panel">
        <div className="history-heading">
          <div><h2>Battery and performance history</h2><p>Indexed samples with long-term hourly rollups.</p></div>
          <div className="period-tabs" aria-label="History period">
            {periods.map((item) => <button key={item.value} className={period === item.value ? "active" : ""} onClick={() => setPeriod(item.value)}>{item.label}</button>)}
          </div>
        </div>
        <div className="chart-grid">
          <HistoryChart
            title="Energy position"
            points={history}
            first={{ key: "batteryPercent", label: "SOC", unit: "%", color: "var(--accent)" }}
            second={{ key: "rangeKm", label: "OEM range", unit: "km", color: "#64b8e8" }}
          />
          <HistoryChart
            title="Observed peaks"
            points={history}
            first={{ key: "peakSpeedKph", label: "Speed", unit: "km/h", color: "var(--accent)" }}
            second={{ key: "chargingPowerKw", label: "Charge estimate", unit: "kW", color: "#64b8e8" }}
          />
        </div>
      </section>

      <section className="telemetry-storage">
        <Database size={26} />
        <div><strong>Bounded telemetry archive</strong><p>Raw samples: {statistics?.storage.rawSamples.toLocaleString() ?? "0"} of {statistics?.storage.rawSampleCap.toLocaleString() ?? "800,000"}. Hourly rollups: {statistics?.storage.hourlyRollups.toLocaleString() ?? "0"}.</p></div>
        <div className="telemetry-storage-summary"><strong>{formatBytes(statistics?.storage.estimatedBytes ?? 0)}</strong><span>{statistics?.storage.rawRetentionDays ?? 90} days raw, {statistics?.storage.rollupRetentionYears ?? 10} years rolled up</span></div>
        <button className="secondary-button telemetry-clear-button" onClick={() => setClearDialog(true)}><Trash size={20} />Clear statistics</button>
      </section>

      <footer className="telemetry-footer">
        <span>Sources: factory SAIC vehicle service and live properties, queried directly over ADB</span>
        <span>{telemetry ? `Updated ${new Date(telemetry.collectedAt).toLocaleTimeString()}` : "Waiting for telemetry"}</span>
      </footer>

      {clearDialog && <div className="modal-backdrop" onMouseDown={() => !clearing && setClearDialog(false)}>
        <div className="confirm-dialog telemetry-clear-dialog" role="dialog" aria-modal="true" aria-labelledby="clear-statistics-title" onMouseDown={(event) => event.stopPropagation()}>
          <h2 id="clear-statistics-title">Clear car statistics</h2>
          <p>Choose whether to keep your long-term records. This cannot be undone.</p>
          <div className="clear-statistics-options">
            <button className="secondary-button" onClick={() => void clearStatistics("history")} disabled={Boolean(clearing)}>
              <span>{clearing === "history" ? "Clearing..." : "Clear data, keep all-time info"}</span>
              <small>Deletes graphs and stored history. Keeps peaks, tracked totals, charging sessions, and range learning.</small>
            </button>
            <button className="danger-button" onClick={() => void clearStatistics("all")} disabled={Boolean(clearing)}>
              <span>{clearing === "all" ? "Clearing..." : "Clear ALL data"}</span>
              <small>Deletes history and resets every peak, total, counter, and learned estimate.</small>
            </button>
          </div>
          <div className="dialog-actions"><button className="secondary-button" onClick={() => setClearDialog(false)} disabled={Boolean(clearing)}>Cancel</button></div>
        </div>
      </div>}
    </div>
  );
}

type ChartKey = "batteryPercent" | "rangeKm" | "peakSpeedKph" | "chargingPowerKw";
type ChartSeries = { key: ChartKey; label: string; unit: string; color: string };

function HistoryChart({ title, points, first, second }: { title: string; points: TelemetryHistoryPoint[]; first: ChartSeries; second: ChartSeries }) {
  const width = 900;
  const height = 230;
  const padding = 28;
  const timestamps = points.map((point) => point.timestamp);
  const start = Math.min(...timestamps);
  const end = Math.max(...timestamps);
  const coordinates = (series: ChartSeries) => {
    const values = points.map((point) => point[series.key]).filter((item): item is number => item !== null);
    if (values.length === 0) return { path: "", minimum: 0, maximum: 0 };
    const minimum = Math.min(...values);
    const maximum = Math.max(...values);
    const spread = Math.max(maximum - minimum, 1);
    const path = points
      .filter((point) => point[series.key] !== null)
      .map((point) => {
        const x = padding + ((point.timestamp - start) / Math.max(end - start, 1)) * (width - padding * 2);
        const y = height - padding - (((point[series.key] as number) - minimum) / spread) * (height - padding * 2);
        return `${x.toFixed(1)},${y.toFixed(1)}`;
      })
      .join(" ");
    return { path, minimum, maximum };
  };
  const firstLine = coordinates(first);
  const secondLine = coordinates(second);

  return <article className="history-chart">
    <div><h3>{title}</h3><div className="chart-legend"><span style={{ color: first.color }}>{first.label}</span><span style={{ color: second.color }}>{second.label}</span></div></div>
    {points.length < 2 ? <div className="chart-empty">Collecting enough samples to draw this period.</div> : <>
      <svg viewBox={`0 0 ${width} ${height}`} role="img" aria-label={`${first.label} and ${second.label} history`}>
        {[0.25, 0.5, 0.75].map((ratio) => <line key={ratio} x1={padding} y1={height * ratio} x2={width - padding} y2={height * ratio} className="chart-guide" />)}
        <polyline points={firstLine.path} fill="none" stroke={first.color} strokeWidth="4" vectorEffect="non-scaling-stroke" />
        <polyline points={secondLine.path} fill="none" stroke={second.color} strokeWidth="3" vectorEffect="non-scaling-stroke" />
      </svg>
      <div className="chart-scale"><span>{firstLine.minimum.toFixed(0)}-{firstLine.maximum.toFixed(0)} {first.unit}</span><span>{secondLine.minimum.toFixed(0)}-{secondLine.maximum.toFixed(0)} {second.unit}</span></div>
    </>}
  </article>;
}

function TelemetryValue({ icon, label, value: availability, suffix, decimals = 0 }: { icon: React.ReactNode; label: string; value: Availability<number> | undefined; suffix: string; decimals?: number }) {
  return <article className="energy-value">{icon}<span>{label}</span><strong>{availability?.available ? `${availability.value.toFixed(decimals)} ${suffix}` : "Unavailable"}</strong><small>{availability && !availability.available ? availability.reason : "Live vehicle value"}</small></article>;
}

function RecordCard({ icon, label, value, note }: { icon: React.ReactNode; label: string; value: string; note: string }) {
  return <article>{icon}<span>{label}</span><strong>{value}</strong><small>{note}</small></article>;
}

function formatMetric(value: number | null | undefined, unit: string, decimals = 0): string {
  return value === null || value === undefined ? "Learning" : `${value.toFixed(decimals)} ${unit}`;
}

function recordedDate(timestamp: number | null | undefined): string {
  return timestamp ? `Recorded ${new Date(timestamp).toLocaleDateString()}` : "No record yet";
}

function formatDuration(seconds: number): string {
  const hours = Math.floor(seconds / 3_600);
  const minutes = Math.floor((seconds % 3_600) / 60);
  return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
}

function formatBytes(bytes: number): string {
  if (bytes < 1024 * 1024) return `${Math.max(bytes / 1024, 0).toFixed(0)} KB`;
  return `${(bytes / 1024 / 1024).toFixed(1)} MB estimated`;
}
