"use client";

import { useEffect, useState, useCallback } from "react";
import { toast } from "sonner";
import {
  fetchRackEnvReadings, fetchHumidityHistory, fetchTempHistory as fetchRoomTempHistory,
  fetchCracStatus, fetchLeakStatus, fetchFireStatus, fetchParticleStatus,
  type RoomEnvReadings, type HumidityBucket, type TempBucket, type CracStatus,
  type LeakSensorStatus, type FireZoneStatus, type ParticleStatus,
} from "@/lib/api";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useThresholds } from "@/lib/threshold-context";
import { TimeRangePicker } from "@/components/ui/time-range-picker";
import {
  ComposedChart, Line, XAxis, YAxis, CartesianGrid, Tooltip,
  ResponsiveContainer, ReferenceLine, ReferenceArea,
} from "recharts";
import { Thermometer, Droplets, WifiOff, CheckCircle2, AlertTriangle, Flame, Wind } from "lucide-react";
import { RackDetailSheet } from "@/components/dashboard/rack-detail-sheet";
import { cn } from "@/lib/utils";
import Link from "next/link";

const SITE_ID = "sg-01";
const ROOM_COLORS: Record<string, { temp: string; hum: string }> = {
  "hall-a": { temp: "oklch(0.62 0.17 212)", hum: "oklch(0.55 0.18 270)" },
  "hall-b": { temp: "oklch(0.7 0.15 162)",  hum: "oklch(0.60 0.15 145)" },
};
const roomLabels: Record<string, string> = { "hall-a": "Hall A", "hall-b": "Hall B" };

function formatTime(iso: string) {
  return new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
}

// ── Utility functions ─────────────────────────────────────────────────────────

/** Magnus formula dew point (°C) from temperature (°C) and relative humidity (%) */
function dewPoint(temp: number, rh: number): number {
  const gamma = Math.log(rh / 100) + (17.625 * temp) / (243.04 + temp);
  return Math.round((243.04 * gamma / (17.625 - gamma)) * 10) / 10;
}

function humidityColor(hum: number | null): string {
  if (hum === null) return "oklch(0.25 0.02 265)";
  if (hum > 80)  return "oklch(0.55 0.22 25)";   // critical high
  if (hum > 65)  return "oklch(0.65 0.20 45)";   // warning high
  if (hum > 50)  return "oklch(0.72 0.18 84)";   // elevated
  if (hum >= 30) return "oklch(0.68 0.14 162)";  // optimal
  return "oklch(0.62 0.17 212)";                  // low (static risk)
}

// ── Temperature heatmap ───────────────────────────────────────────────────────

function tempColor(temp: number | null, warn = 26, crit = 28): string {
  if (temp === null) return "oklch(0.25 0.02 265)";
  if (temp >= crit + 4) return "oklch(0.55 0.22 25)";
  if (temp >= crit)     return "oklch(0.65 0.20 45)";
  if (temp >= warn)     return "oklch(0.72 0.18 84)";
  if (temp >= warn - 2) return "oklch(0.78 0.14 140)";
  if (temp >= warn - 4) return "oklch(0.68 0.14 162)";
  return "oklch(0.60 0.15 212)";
}

type HeatmapOverlay = "temp" | "humidity";

function TempHeatmap({
  rooms, onRackClick, activeRoom, tempWarn = 26, tempCrit = 28, humWarn = 65, humCrit = 80,
}: {
  rooms: RoomEnvReadings[];
  onRackClick: (rackId: string) => void;
  activeRoom: string;
  tempWarn?: number;
  tempCrit?: number;
  humWarn?: number;
  humCrit?: number;
}) {
  const [overlay, setOverlay] = useState<HeatmapOverlay>("temp");
  const room = rooms.find((r) => r.room_id === activeRoom);

  return (
    <Card>
      <CardHeader className="pb-2">
        <div className="flex items-center justify-between flex-wrap gap-2">
          <CardTitle className="text-sm font-semibold flex items-center gap-2">
            {overlay === "temp"
              ? <Thermometer className="w-4 h-4 text-primary" />
              : <Droplets className="w-4 h-4 text-blue-400" />}
            {overlay === "temp" ? "Temperature" : "Humidity"} Heatmap
          </CardTitle>
          <div className="flex items-center gap-2">
            {/* Overlay toggle */}
            <div className="flex items-center gap-0.5 rounded-md border border-border p-0.5">
              <button
                onClick={() => setOverlay("temp")}
                aria-label="Temperature overlay"
                aria-pressed={overlay === "temp"}
                className={cn(
                  "flex items-center gap-1 px-2 py-0.5 rounded text-[10px] font-medium transition-colors",
                  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
                  overlay === "temp" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground"
                )}
              >
                <Thermometer className="w-3 h-3" /> Temp
              </button>
              <button
                onClick={() => setOverlay("humidity")}
                aria-label="Humidity overlay"
                aria-pressed={overlay === "humidity"}
                className={cn(
                  "flex items-center gap-1 px-2 py-0.5 rounded text-[10px] font-medium transition-colors",
                  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
                  overlay === "humidity" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground"
                )}
              >
                <Droplets className="w-3 h-3" /> Humidity
              </button>
            </div>
          </div>
        </div>
      </CardHeader>
      <CardContent className="space-y-4">
        {/* Callout — hottest or most humid */}
        {(() => {
          if (overlay === "temp") {
            const hottest = room?.racks.reduce((a, b) =>
              (a.temperature ?? 0) > (b.temperature ?? 0) ? a : b
            );
            if (!hottest || hottest.temperature === null) return null;
            const isHot = hottest.temperature >= tempWarn;
            return (
              <div className={cn(
                "flex items-center gap-2 rounded-lg px-3 py-2 text-xs",
                hottest.temperature >= tempCrit ? "bg-destructive/10 text-destructive" :
                isHot ? "bg-amber-500/10 text-amber-400" : "bg-muted/40 text-muted-foreground"
              )}>
                <Thermometer className="w-3.5 h-3.5 shrink-0" />
                <span>
                  Hottest: <strong>{hottest.rack_id.toUpperCase()}</strong> at <strong>{hottest.temperature}°C</strong>
                  {hottest.temperature >= tempCrit ? " — above critical threshold" : isHot ? " — above warning threshold" : " — within normal range"}
                </span>
              </div>
            );
          } else {
            const humid = room?.racks.reduce((a, b) =>
              (a.humidity ?? 0) > (b.humidity ?? 0) ? a : b
            );
            if (!humid || humid.humidity === null) return null;
            const isHigh = humid.humidity > humWarn;
            return (
              <div className={cn(
                "flex items-center gap-2 rounded-lg px-3 py-2 text-xs",
                humid.humidity > humCrit ? "bg-destructive/10 text-destructive" :
                isHigh ? "bg-amber-500/10 text-amber-400" : "bg-muted/40 text-muted-foreground"
              )}>
                <Droplets className="w-3.5 h-3.5 shrink-0" />
                <span>
                  Highest humidity: <strong>{humid.rack_id.toUpperCase()}</strong> at <strong>{humid.humidity}%</strong>
                  {humid.humidity > humCrit ? " — above critical threshold" : isHigh ? " — above warning threshold" : " — within normal range"}
                </span>
              </div>
            );
          }
        })()}

        {/* Rack grid */}
        <div className="grid grid-cols-5 gap-2">
          {room?.racks.map((rack) => {
            const offline = rack.temperature === null && rack.humidity === null;
            const bg = overlay === "temp" ? tempColor(rack.temperature, tempWarn, tempCrit) : humidityColor(rack.humidity);
            const mainVal = overlay === "temp"
              ? (rack.temperature !== null ? `${rack.temperature}°` : null)
              : (rack.humidity !== null ? `${rack.humidity}%` : null);
            const subVal = overlay === "temp"
              ? (rack.humidity !== null && rack.temperature !== null
                  ? `DP ${dewPoint(rack.temperature, rack.humidity)}°` : null)
              : (rack.temperature !== null ? `${rack.temperature}°C` : null);

            return (
              <div
                key={rack.rack_id}
                onClick={() => onRackClick(rack.rack_id)}
                className={cn(
                  "relative rounded-lg p-3 flex flex-col items-center justify-center gap-0.5 min-h-[72px] transition-all cursor-pointer hover:ring-2 hover:ring-white/20",
                  offline ? "hover:opacity-70" : "hover:opacity-80"
                )}
                style={{
                  backgroundColor: offline ? "oklch(0.22 0.02 265)" : bg,
                  backgroundImage: offline
                    ? "repeating-linear-gradient(45deg, transparent, transparent 4px, oklch(1 0 0 / 4%) 4px, oklch(1 0 0 / 4%) 8px)"
                    : undefined,
                }}
              >
                <span className="text-[10px] font-semibold text-white/70">
                  {rack.rack_id.replace("rack-", "").toUpperCase()}
                </span>
                {offline ? (
                  <WifiOff className="w-3.5 h-3.5 text-white/40" />
                ) : (
                  <span className="text-base font-bold text-white">{mainVal ?? "—"}</span>
                )}
                {subVal && (
                  <span className="text-[10px] text-white/60">{subVal}</span>
                )}
              </div>
            );
          })}
        </div>

        {/* Legend */}
        <div className="flex items-center gap-1 text-[10px] text-muted-foreground">
          {overlay === "temp" ? (
            <>
              <span>Cool</span>
              {(["oklch(0.60 0.15 212)", "oklch(0.68 0.14 162)", "oklch(0.78 0.14 140)", "oklch(0.72 0.18 84)", "oklch(0.65 0.20 45)", "oklch(0.55 0.22 25)"] as string[]).map((c, i) => (
                <span key={i} className="w-6 h-3 rounded-sm inline-block" style={{ backgroundColor: c }} />
              ))}
              <span>Hot</span>
              <span className="ml-auto">Warn: {tempWarn}°C &nbsp;|&nbsp; Crit: {tempCrit}°C · Tiles show dew point (DP)</span>
            </>
          ) : (
            <>
              <span>Dry</span>
              {(["oklch(0.62 0.17 212)", "oklch(0.68 0.14 162)", "oklch(0.72 0.18 84)", "oklch(0.65 0.20 45)", "oklch(0.55 0.22 25)"] as string[]).map((c, i) => (
                <span key={i} className="w-6 h-3 rounded-sm inline-block" style={{ backgroundColor: c }} />
              ))}
              <span>Humid</span>
              <span className="ml-auto">Optimal: 30–65% &nbsp;|&nbsp; ASHRAE A1 max: 80%</span>
            </>
          )}
        </div>
      </CardContent>
    </Card>
  );
}

// ── Dual-axis trend chart ─────────────────────────────────────────────────────

function EnvTrendChart({
  tempData, humData, hours, activeRoom, tempWarn = 26, tempCrit = 28, humWarn = 65,
}: {
  tempData: TempBucket[];
  humData: HumidityBucket[];
  hours: number;
  activeRoom: string;
  tempWarn?: number;
  tempCrit?: number;
  humWarn?: number;
}) {
  const roomIds = [...new Set(tempData.map((d) => d.room_id))].sort();

  // Build combined rows for the active room
  type ComboRow = { time: string; temp: number | null; hum: number | null };
  const buckets = new Map<string, ComboRow>();

  for (const d of tempData.filter((d) => d.room_id === activeRoom)) {
    const time = formatTime(d.bucket);
    if (!buckets.has(time)) buckets.set(time, { time, temp: null, hum: null });
    buckets.get(time)!.temp = d.avg_temp;
  }
  for (const d of humData.filter((d) => d.room_id === activeRoom)) {
    const time = formatTime(d.bucket);
    if (!buckets.has(time)) buckets.set(time, { time, temp: null, hum: null });
    buckets.get(time)!.hum = d.avg_humidity;
  }
  const chartData = Array.from(buckets.values());
  const colors = ROOM_COLORS[activeRoom] ?? ROOM_COLORS["hall-a"];

  const labelSuffix = hours <= 1 ? "1h" : hours <= 6 ? "6h" : hours <= 24 ? "24h" : "7d";

  return (
    <Card>
      <CardHeader className="pb-2">
        <div className="flex items-center justify-between flex-wrap gap-2">
          <CardTitle className="text-sm font-semibold flex items-center gap-2">
            <Thermometer className="w-4 h-4 text-primary" />
            <Droplets className="w-4 h-4 text-blue-400" />
            Temp &amp; Humidity — last {labelSuffix}
          </CardTitle>
        </div>
        {/* Legend */}
        <div className="flex items-center gap-4 text-[10px] text-muted-foreground mt-1 flex-wrap">
          <span className="flex items-center gap-1.5">
            <span className="w-4 h-0.5 inline-block rounded" style={{ backgroundColor: colors.temp }} />
            Temp (°C, left axis)
          </span>
          <span className="flex items-center gap-1.5">
            <span className="w-4 h-0.5 inline-block rounded border-t-2 border-dashed" style={{ borderColor: colors.hum }} />
            Humidity (%, right axis)
          </span>
          <span className="flex items-center gap-1.5 ml-auto">
            <span className="w-4 h-3 inline-block rounded opacity-40" style={{ backgroundColor: "#22c55e" }} />
            ASHRAE A1 safe zone
          </span>
        </div>
      </CardHeader>
      <CardContent>
        {chartData.length === 0 ? (
          <div className="h-[240px] flex items-center justify-center text-sm text-muted-foreground">
            Waiting for data...
          </div>
        ) : (
          <ResponsiveContainer width="100%" height={240}>
            <ComposedChart data={chartData} margin={{ top: 4, right: 30, left: -16, bottom: 0 }}>
              {/* ASHRAE A1 safe zones */}
              <ReferenceArea yAxisId="temp" y1={18} y2={27} fill="#22c55e" fillOpacity={0.07} />
              <ReferenceArea yAxisId="hum"  y1={20} y2={80} fill="#3b82f6" fillOpacity={0.05} />

              <CartesianGrid strokeDasharray="3 3" stroke="oklch(1 0 0 / 8%)" />
              <XAxis
                dataKey="time"
                tick={{ fontSize: 10, fill: "oklch(0.65 0.04 257)" }}
                tickLine={false}
                axisLine={false}
              />
              {/* Left axis — temperature */}
              <YAxis
                yAxisId="temp"
                domain={[16, 36]}
                tick={{ fontSize: 10, fill: "oklch(0.65 0.04 257)" }}
                tickLine={false}
                axisLine={false}
                tickFormatter={(v) => `${v}°`}
              />
              {/* Right axis — humidity */}
              <YAxis
                yAxisId="hum"
                orientation="right"
                domain={[0, 100]}
                tick={{ fontSize: 10, fill: "oklch(0.65 0.04 257)" }}
                tickLine={false}
                axisLine={false}
                tickFormatter={(v) => `${v}%`}
              />
              <Tooltip
                contentStyle={{ backgroundColor: "oklch(0.16 0.04 265)", border: "1px solid oklch(1 0 0 / 9%)", borderRadius: "6px", fontSize: "12px" }}
                formatter={(v, name) =>
                  name === "temp" ? [`${Number(v).toFixed(1)}°C`, "Temperature"] :
                  [`${Number(v).toFixed(0)}%`, "Humidity"]
                }
              />

              {/* Temp reference lines */}
              <ReferenceLine yAxisId="temp" y={tempWarn} stroke="oklch(0.72 0.18 84)" strokeDasharray="4 4" strokeWidth={1}
                label={{ value: `Warn ${tempWarn}°`, fontSize: 9, fill: "oklch(0.72 0.18 84)", position: "right" }} />
              <ReferenceLine yAxisId="temp" y={tempCrit} stroke="oklch(0.55 0.22 25)" strokeDasharray="4 4" strokeWidth={1}
                label={{ value: `Crit ${tempCrit}°`, fontSize: 9, fill: "oklch(0.55 0.22 25)", position: "right" }} />

              {/* Humidity reference line */}
              <ReferenceLine yAxisId="hum" y={humWarn} stroke="oklch(0.62 0.17 212)" strokeDasharray="4 4" strokeWidth={1} />

              {/* Lines */}
              <Line
                yAxisId="temp"
                type="monotone"
                dataKey="temp"
                stroke={colors.temp}
                strokeWidth={2}
                dot={false}
                activeDot={{ r: 4 }}
                connectNulls
              />
              <Line
                yAxisId="hum"
                type="monotone"
                dataKey="hum"
                stroke={colors.hum}
                strokeWidth={2}
                strokeDasharray="6 3"
                dot={false}
                activeDot={{ r: 4 }}
                connectNulls
              />
            </ComposedChart>
          </ResponsiveContainer>
        )}
        <p className="text-[10px] text-muted-foreground mt-2">
          Green shaded band = ASHRAE A1 thermal envelope (18–27°C / 20–80% RH)
        </p>
      </CardContent>
    </Card>
  );
}

// ── ASHRAE A1 Compliance Table ────────────────────────────────────────────────

// ASHRAE A1: 15–32°C, 20–80% RH
function AshraeTable({ rooms }: { rooms: RoomEnvReadings[] }) {
  const allRacks = rooms.flatMap(r =>
    r.racks.map(rack => ({ ...rack, room_id: r.room_id }))
  ).filter(r => r.temperature !== null || r.humidity !== null);

  type Issue = { type: string; detail: string };
  const rows = allRacks.map(rack => {
    const issues: Issue[] = [];
    if (rack.temperature !== null) {
      if (rack.temperature < 15) issues.push({ type: "Temp", detail: `${rack.temperature}°C — below 15°C min` });
      if (rack.temperature > 32) issues.push({ type: "Temp", detail: `${rack.temperature}°C — above 32°C max` });
    }
    if (rack.humidity !== null) {
      if (rack.humidity < 20) issues.push({ type: "RH", detail: `${rack.humidity}% — below 20% min` });
      if (rack.humidity > 80) issues.push({ type: "RH", detail: `${rack.humidity}% — above 80% max` });
    }
    const dp = rack.temperature !== null && rack.humidity !== null
      ? dewPoint(rack.temperature, rack.humidity) : null;
    return { rack, issues, dp };
  });

  const violations = rows.filter(r => r.issues.length > 0);
  const compliant  = rows.filter(r => r.issues.length === 0);

  return (
    <Card>
      <CardHeader className="pb-2">
        <div className="flex items-center justify-between">
          <CardTitle className="text-sm font-semibold flex items-center gap-2">
            <CheckCircle2 className="w-4 h-4 text-primary" /> ASHRAE A1 Compliance
          </CardTitle>
          <span className={cn(
            "text-[10px] font-semibold px-2 py-0.5 rounded-full",
            violations.length > 0 ? "bg-destructive/10 text-destructive" : "bg-green-500/10 text-green-400"
          )}>
            {violations.length === 0 ? `All ${compliant.length} racks compliant` : `${violations.length} violation${violations.length > 1 ? "s" : ""}`}
          </span>
        </div>
      </CardHeader>
      <CardContent>
        {violations.length === 0 ? (
          <p className="text-sm text-green-400 flex items-center gap-2">
            <CheckCircle2 className="w-4 h-4" />
            All racks within ASHRAE A1 envelope (15–32°C, 20–80% RH)
          </p>
        ) : (
          <div className="space-y-2">
            {violations.map(({ rack, issues, dp }) => (
              <div key={rack.rack_id} className="flex items-start gap-3 rounded-lg bg-destructive/5 border border-destructive/20 px-3 py-2 text-xs">
                <AlertTriangle className="w-3.5 h-3.5 text-destructive mt-0.5 shrink-0" />
                <div className="flex-1">
                  <span className="font-semibold">{rack.rack_id.toUpperCase()}</span>
                  <span className="text-muted-foreground ml-2">{roomLabels[rack.room_id] ?? rack.room_id}</span>
                  <div className="flex flex-wrap gap-x-4 gap-y-0.5 mt-0.5 text-destructive">
                    {issues.map((iss, i) => <span key={i}>{iss.type}: {iss.detail}</span>)}
                    {dp !== null && <span className="text-muted-foreground">DP: {dp}°C</span>}
                  </div>
                </div>
              </div>
            ))}
            <p className="text-[10px] text-muted-foreground pt-1">
              ASHRAE A1 envelope: 15–32°C dry bulb, 20–80% relative humidity
            </p>
          </div>
        )}
      </CardContent>
    </Card>
  );
}

// ── Dew Point Panel ───────────────────────────────────────────────────────────

function DewPointPanel({
  rooms, cracs, activeRoom,
}: {
  rooms: RoomEnvReadings[];
  cracs: CracStatus[];
  activeRoom: string;
}) {
  const room = rooms.find(r => r.room_id === activeRoom);
  const crac = cracs.find(c => c.room_id === activeRoom);
  const supplyTemp = crac?.supply_temp ?? null;

  const rackDps = (room?.racks ?? [])
    .filter(r => r.temperature !== null && r.humidity !== null)
    .map(r => ({
      rack_id: r.rack_id,
      dp: dewPoint(r.temperature!, r.humidity!),
      temp: r.temperature!,
      hum: r.humidity!,
    }))
    .sort((a, b) => b.dp - a.dp);

  return (
    <Card>
      <CardHeader className="pb-2">
        <div className="flex items-center justify-between flex-wrap gap-2">
          <CardTitle className="text-sm font-semibold flex items-center gap-2">
            <Droplets className="w-4 h-4 text-blue-400" /> Dew Point by Rack
          </CardTitle>
          {supplyTemp !== null && (
            <span className="text-[10px] text-muted-foreground">
              CRAC supply: <strong className="text-blue-400">{supplyTemp}°C</strong>
              {rackDps.some(r => r.dp >= supplyTemp - 1) && (
                <span className="text-destructive ml-1">— condensation risk!</span>
              )}
            </span>
          )}
        </div>
      </CardHeader>
      <CardContent>
        {rackDps.length === 0 ? (
          <p className="text-sm text-muted-foreground">No data available</p>
        ) : (
          <div className="space-y-1.5">
            {rackDps.map(({ rack_id, dp, temp, hum }) => {
              const nearCondensation = supplyTemp !== null && dp >= supplyTemp - 1;
              const dpColor = nearCondensation ? "text-destructive"
                : dp > 15 ? "text-amber-400" : "text-foreground";
              return (
                <div key={rack_id} className="flex items-center gap-3 text-xs">
                  <span className="font-mono w-16 shrink-0 text-muted-foreground">
                    {rack_id.replace("rack-", "").toUpperCase()}
                  </span>
                  <div className="flex-1 h-1.5 rounded-full bg-muted overflow-hidden">
                    <div
                      className={cn("h-full rounded-full transition-all", nearCondensation ? "bg-destructive" : dp > 15 ? "bg-amber-500" : "bg-blue-500")}
                      style={{ width: `${Math.min(100, Math.max(0, (dp / 30) * 100))}%` }}
                    />
                  </div>
                  <span className={cn("font-mono font-semibold w-16 text-right", dpColor)}>
                    {dp}°C DP
                  </span>
                  <span className="text-muted-foreground w-20 text-right hidden sm:block">
                    {temp}° / {hum}%
                  </span>
                </div>
              );
            })}
            <p className="text-[10px] text-muted-foreground pt-1">
              Dew point approaching CRAC supply temp = condensation risk on cold surfaces
            </p>
          </div>
        )}
      </CardContent>
    </Card>
  );
}

// ── Leak sensor panel ─────────────────────────────────────────────────────────

function LeakPanel({ sensors }: { sensors: LeakSensorStatus[] }) {
  const detected = sensors.filter(s => s.state === "detected");
  const anyDetected = detected.length > 0;

  return (
    <Card className={cn("border", anyDetected && "border-destructive/50")}>
      <CardHeader className="pb-2">
        <div className="flex items-center justify-between">
          <CardTitle className="text-sm font-semibold flex items-center gap-2">
            <Droplets className="w-4 h-4 text-blue-400" /> Water / Leak Detection
          </CardTitle>
          <div className="flex items-center gap-2">
            <Link href="/leak" className="text-[10px] text-primary hover:underline">View full page →</Link>
            <span className={cn("text-[10px] font-semibold px-2 py-0.5 rounded-full uppercase tracking-wide",
              anyDetected ? "bg-destructive/10 text-destructive animate-pulse" : "bg-green-500/10 text-green-400",
            )}>
              {anyDetected ? `${detected.length} leak detected` : "All clear"}
            </span>
          </div>
        </div>
      </CardHeader>
      <CardContent className="space-y-2">
        {sensors.map(s => {
          const detected = s.state === "detected";
          return (
            <div key={s.sensor_id} className={cn(
              "flex items-start justify-between rounded-lg px-3 py-2 text-xs",
              detected ? "bg-destructive/10" : "bg-muted/30",
            )}>
              <div>
                <p className={cn("font-semibold", detected ? "text-destructive" : "text-foreground")}>
                  {detected ? <AlertTriangle className="w-3 h-3 inline mr-1" /> : <CheckCircle2 className="w-3 h-3 inline mr-1 text-green-400" />}
                  {s.sensor_id}
                </p>
                <p className="text-muted-foreground mt-0.5">
                  Zone: {s.floor_zone}
                  {s.under_floor ? " · under-floor" : ""}
                  {s.near_crac ? " · near CRAC" : ""}
                  {s.room_id ? ` · ${s.room_id}` : ""}
                </p>
              </div>
              <span className={cn("font-semibold shrink-0 ml-2", detected ? "text-destructive" : "text-green-400")}>
                {s.state === "detected" ? "DETECTED" : s.state === "clear" ? "Clear" : "Unknown"}
              </span>
            </div>
          );
        })}
        {sensors.length === 0 && (
          <p className="text-sm text-muted-foreground text-center py-2">No sensors configured</p>
        )}
      </CardContent>
    </Card>
  );
}

// ── VESDA / Fire panel ────────────────────────────────────────────────────────

const VESDA_LEVEL_CONFIG: Record<string, { label: string; color: string; bg: string }> = {
  normal: { label: "Normal", color: "text-green-400",      bg: "bg-green-500/10" },
  alert:  { label: "Alert",  color: "text-amber-400",      bg: "bg-amber-500/10" },
  action: { label: "Action", color: "text-orange-400",     bg: "bg-orange-500/10" },
  fire:   { label: "FIRE",   color: "text-destructive",    bg: "bg-destructive/10" },
};

function FirePanel({ zones }: { zones: FireZoneStatus[] }) {
  const elevated = zones.filter(z => z.level !== "normal");

  return (
    <Card className={cn("border", elevated.length > 0 && elevated.some(z => z.level === "fire") && "border-destructive/50")}>
      <CardHeader className="pb-2">
        <div className="flex items-center justify-between">
          <CardTitle className="text-sm font-semibold flex items-center gap-2">
            <Flame className="w-4 h-4 text-orange-400" /> VESDA / Smoke Detection
          </CardTitle>
          <div className="flex items-center gap-2">
            <Link href="/fire" className="text-[10px] text-primary hover:underline">View full page →</Link>
            <span className={cn("text-[10px] font-semibold px-2 py-0.5 rounded-full uppercase tracking-wide",
              elevated.length === 0 ? "bg-green-500/10 text-green-400" :
              zones.some(z => z.level === "fire") ? "bg-destructive/10 text-destructive animate-pulse" :
              "bg-amber-500/10 text-amber-400",
            )}>
              {elevated.length === 0 ? "All normal" : `${elevated.length} zone${elevated.length !== 1 ? "s" : ""} elevated`}
            </span>
          </div>
        </div>
      </CardHeader>
      <CardContent className="space-y-2">
        {zones.map(zone => {
          const cfg = VESDA_LEVEL_CONFIG[zone.level] ?? VESDA_LEVEL_CONFIG.normal;
          return (
            <div key={zone.zone_id} className={cn("rounded-lg px-3 py-2 text-xs", cfg.bg)}>
              <div className="flex items-center justify-between mb-1.5">
                <div>
                  <p className="font-semibold">{zone.zone_id}</p>
                  {zone.room_id && <p className="text-muted-foreground">{zone.room_id}</p>}
                </div>
                <span className={cn("font-bold text-sm uppercase", cfg.color)}>{cfg.label}</span>
              </div>
              <div className="flex items-center justify-between">
                <span className="text-muted-foreground">
                  Obscuration: <strong className={cn(zone.level !== "normal" ? cfg.color : "")}>{zone.obscuration_pct_m != null ? `${zone.obscuration_pct_m.toFixed(3)} %/m` : "—"}</strong>
                </span>
                <div className="flex gap-2 text-[10px]">
                  {!zone.detector_1_ok && <span className="text-destructive">Det1 fault</span>}
                  {!zone.detector_2_ok && <span className="text-destructive">Det2 fault</span>}
                  {!zone.power_ok    && <span className="text-destructive">Power fault</span>}
                  {!zone.flow_ok     && <span className="text-destructive">Flow fault</span>}
                  {zone.detector_1_ok && zone.detector_2_ok && zone.power_ok && zone.flow_ok && (
                    <span className="text-green-400">Systems OK</span>
                  )}
                </div>
              </div>
            </div>
          );
        })}
        {zones.length === 0 && (
          <p className="text-sm text-muted-foreground text-center py-2">No VESDA zones configured</p>
        )}
      </CardContent>
    </Card>
  );
}

// ── Particle count panel (ISO 14644) ──────────────────────────────────────────

const ISO_LABELS: Record<number, { label: string; color: string }> = {
  5: { label: "ISO 5",  color: "text-green-400"  },
  6: { label: "ISO 6",  color: "text-green-400"  },
  7: { label: "ISO 7",  color: "text-green-400"  },
  8: { label: "ISO 8",  color: "text-amber-400"  },
  9: { label: "ISO 9",  color: "text-destructive" },
};

const ISO8_0_5UM = 3_520_000;
const ISO8_5UM   =    29_300;

function ParticlePanel({ rooms }: { rooms: ParticleStatus[] }) {
  if (rooms.length === 0) return null;
  return (
    <Card>
      <CardHeader className="pb-2">
        <CardTitle className="text-sm font-semibold flex items-center gap-2">
          <Wind className="w-4 h-4 text-primary" />
          Air Quality — ISO 14644
        </CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        {rooms.map(r => {
          const cls = r.iso_class ? ISO_LABELS[r.iso_class] : null;
          const p05pct = r.particles_0_5um !== null ? Math.min(100, (r.particles_0_5um / ISO8_0_5UM) * 100) : null;
          const p5pct  = r.particles_5um   !== null ? Math.min(100, (r.particles_5um   / ISO8_5UM)   * 100) : null;
          return (
            <div key={r.room_id} className="space-y-2">
              <div className="flex items-center justify-between">
                <span className="text-sm font-medium">{r.room_id === "hall-a" ? "Hall A" : r.room_id === "hall-b" ? "Hall B" : r.room_id}</span>
                {cls ? (
                  <span className={cn("text-xs font-semibold px-2 py-0.5 rounded-full bg-muted/40", cls.color)}>
                    {cls.label}
                  </span>
                ) : (
                  <span className="text-xs text-muted-foreground">No data</span>
                )}
              </div>
              <div className="space-y-1.5 text-xs text-muted-foreground">
                <div className="flex items-center gap-2">
                  <span className="w-28 shrink-0">≥0.5 µm</span>
                  <div className="flex-1 h-2 rounded-full bg-muted overflow-hidden">
                    {p05pct !== null && (
                      <div
                        className={cn("h-full rounded-full transition-all", p05pct >= 100 ? "bg-destructive" : p05pct >= 70 ? "bg-amber-500" : "bg-green-500")}
                        style={{ width: `${p05pct}%` }}
                      />
                    )}
                  </div>
                  <span className="w-32 text-right font-mono">
                    {r.particles_0_5um !== null ? r.particles_0_5um.toLocaleString() : "—"} /m³
                  </span>
                </div>
                <div className="flex items-center gap-2">
                  <span className="w-28 shrink-0">≥5 µm</span>
                  <div className="flex-1 h-2 rounded-full bg-muted overflow-hidden">
                    {p5pct !== null && (
                      <div
                        className={cn("h-full rounded-full transition-all", p5pct >= 100 ? "bg-destructive" : p5pct >= 70 ? "bg-amber-500" : "bg-green-500")}
                        style={{ width: `${p5pct}%` }}
                      />
                    )}
                  </div>
                  <span className="w-32 text-right font-mono">
                    {r.particles_5um !== null ? r.particles_5um.toLocaleString() : "—"} /m³
                  </span>
                </div>
              </div>
            </div>
          );
        })}
        <p className="text-[10px] text-muted-foreground pt-1">
          DC target: ISO 8 (≤3,520,000 particles ≥0.5 µm/m³ · ≤29,300 ≥5 µm/m³)
        </p>
      </CardContent>
    </Card>
  );
}

// ── Page ──────────────────────────────────────────────────────────────────────

export default function EnvironmentalPage() {
  const { thresholds } = useThresholds();
  const [rooms, setRooms]         = useState<RoomEnvReadings[]>([]);
  const [tempHist, setTempHist]   = useState<TempBucket[]>([]);
  const [humHist, setHumHist]     = useState<HumidityBucket[]>([]);
  const [cracs, setCracs]         = useState<CracStatus[]>([]);
  const [leakSensors, setLeak]    = useState<LeakSensorStatus[]>([]);
  const [fireZones, setFire]      = useState<FireZoneStatus[]>([]);
  const [particles, setParticles] = useState<ParticleStatus[]>([]);
  const [hours, setHours]         = useState(6);
  const [loading, setLoading]     = useState(true);
  const [selectedRack, setSelectedRack] = useState<string | null>(null);
  const [activeRoom, setActiveRoom] = useState("hall-a");

  const load = useCallback(async () => {
    try {
      const [r, t, h, c, l, f, p] = await Promise.all([
        fetchRackEnvReadings(SITE_ID),
        fetchRoomTempHistory(SITE_ID, hours),
        fetchHumidityHistory(SITE_ID, hours),
        fetchCracStatus(SITE_ID),
        fetchLeakStatus(SITE_ID).catch(() => []),
        fetchFireStatus(SITE_ID).catch(() => []),
        fetchParticleStatus(SITE_ID).catch(() => []),
      ]);
      setRooms(r);
      setTempHist(t);
      setHumHist(h);
      setCracs(c);
      setLeak(l);
      setFire(f);
      setParticles(p);
    } catch {
      toast.error("Failed to load environmental data");
    } finally {
      setLoading(false);
    }
  }, [hours]);

  useEffect(() => {
    load();
    const id = setInterval(load, 30_000);
    return () => clearInterval(id);
  }, [load]);

  return (
    <div className="p-6 space-y-6">
      <div className="flex items-start justify-between">
        <div>
          <h1 className="text-xl font-semibold">Environmental Monitoring</h1>
          <p className="text-sm text-muted-foreground">Singapore DC01 — refreshes every 30s</p>
        </div>
        <TimeRangePicker value={hours} onChange={setHours} />
      </div>

      {loading ? (
        <div className="space-y-4">
          <Skeleton className="h-64 w-full" />
          <Skeleton className="h-48 w-full" />
        </div>
      ) : (
        <>
          <RackDetailSheet siteId={SITE_ID} rackId={selectedRack} onClose={() => setSelectedRack(null)} />

          {/* Page-level room tab selector */}
          {rooms.length > 0 && (
            <Tabs value={activeRoom} onValueChange={setActiveRoom}>
              <TabsList>
                {rooms.map(r => (
                  <TabsTrigger key={r.room_id} value={r.room_id} className="px-6">
                    {roomLabels[r.room_id] ?? r.room_id}
                  </TabsTrigger>
                ))}
              </TabsList>
            </Tabs>
          )}

          {rooms.length > 0 && (
            <TempHeatmap rooms={rooms} onRackClick={setSelectedRack} activeRoom={activeRoom}
              tempWarn={thresholds.temp.warn} tempCrit={thresholds.temp.critical}
              humWarn={thresholds.humidity.warn} humCrit={thresholds.humidity.critical} />
          )}
          <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
            {rooms.length > 0 && <AshraeTable rooms={rooms} />}
            {rooms.length > 0 && (
              <DewPointPanel rooms={rooms} cracs={cracs} activeRoom={activeRoom} />
            )}
          </div>
          {/* Leak + VESDA panels */}
          <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
            <LeakPanel sensors={leakSensors} />
            <FirePanel zones={fireZones} />
          </div>
          <EnvTrendChart tempData={tempHist} humData={humHist} hours={hours} activeRoom={activeRoom}
            tempWarn={thresholds.temp.warn} tempCrit={thresholds.temp.critical}
            humWarn={thresholds.humidity.warn} />
          <ParticlePanel rooms={particles} />
        </>
      )}
    </div>
  );
}
