import { useEffect, useMemo, useState } from "react";
import {
    Activity,
    Cloud,
    CloudRain,
    Droplets,
    Eye,
    Sun,
    Zap,
    Thermometer,
    Wind,
    type LucideIcon,
} from "lucide-react";
import sunnyBackground from "../../../assets/weather/Sunny.png";
import partlyCloudyBackground from "../../../assets/weather/Partly Cloudy.png";
import cloudyBackground from "../../../assets/weather/Cloudy.png";
import rainyBackground from "../../../assets/weather/Rainy.png";
import overcastBackground from "../../../assets/weather/Overcast.png";
import foggyBackground from "../../../assets/weather/Foggy.png";
import patchyRainBackground from "../../../assets/weather/Patchy Rain.png";
import thunderstormBackground from "../../../assets/weather/Thunderstorm.png";
import snowBackground from "../../../assets/weather/Snow.png";
import snowstormBackground from "../../../assets/weather/Snowstorm.png";
import { useMeteoModuleStream } from "../hooks/useMeteoModuleStream";
import { useMeteoMultiHistory } from "../hooks/useMeteoMultiHistory";
import { useWeatherForecast } from "../hooks/useWeatherForecast";
import type { WeatherForecastResponse } from "../../../types/weather";
import {
    numericSensorValue,
    selectMeteoSensors,
} from "../domain/meteoSensorSelectors";

import WorkspaceChart, {
    type WorkspaceChartConfig,
    type WorkspaceChartInterval,
    type WorkspaceChartMode,
    type WorkspaceChartTimeRange,
} from "../../../components/charts/WorkspaceChart";

import type { HistorianPoint } from "../components/MeteoHistoryModal";

type MeteoPageProps = {
    theme: "dark" | "light";
};

type ChartPoint = {
    timestamp: string;
    value: number;
};

type ChartSeries = {
    key: HistoryKey;
    title: string;
    shortTitle: string;
    unit: string;
    values: ChartPoint[];
    accent: Accent;
};

type Accent = "amber" | "blue" | "cyan" | "emerald" | "violet";

const HISTORY_HOURS = 6;
const RADIUS = "rounded-[5px]";

const HISTORY_KEYS = {
    temperature: "temperature",
    humidity: "humidity",
    windSpeed: "windSpeed",
    windDirection: "windDirection",
    radiation: "radiation",
} as const;

type HistoryKey = (typeof HISTORY_KEYS)[keyof typeof HISTORY_KEYS];

export function MeteoPage({ theme }: MeteoPageProps) {
    const { sensors } = useMeteoModuleStream();
    const weatherForecast = useWeatherForecast();

    const selected = selectMeteoSensors(sensors);

    const temperature = selected.temperature;
    const humidity = selected.humidity;
    const windDirection = selected.windDirection;
    const windSpeed = selected.windSpeed;
    const radiation = selected.radiation;
    const forecast = weatherForecast.forecast;

    const { pointsByKey, loading: historyLoading } = useMeteoMultiHistory(
        [
            temperature ?? null,
            humidity ?? null,
            windSpeed ?? null,
            windDirection ?? null,
            radiation ?? null,
        ],
        HISTORY_HOURS,
    );
    const [selectedForecastDayIndex, setSelectedForecastDayIndex] = useState(0);

    const forecastDays = forecast?.daily ?? [];
    const selectedForecastDay =
        forecastDays[selectedForecastDayIndex] ?? forecastDays[0] ?? null;

    useEffect(() => {
        if (!forecastDays.length) {
            setSelectedForecastDayIndex(0);
            return;
        }

        if (selectedForecastDayIndex > forecastDays.length - 1) {
            setSelectedForecastDayIndex(0);
        }
    }, [forecastDays.length, selectedForecastDayIndex]);

    // Live station readings only. Forecast values are handled by WeatherHeroPanel.
    const currentTemperature = numericSensorValue(temperature);
    const currentHumidity = numericSensorValue(humidity);
    const currentWindSpeed = numericSensorValue(windSpeed);
    const currentRadiation = numericSensorValue(radiation);
    const currentWindDirection = numericSensorValue(windDirection);
    const currentDewPoint = calculateDewPoint(
        currentTemperature,
        currentHumidity,
    );

    const chartSeries = useMemo(
        () => [
            {
                key: HISTORY_KEYS.temperature,
                title: "Temperatura (°C)",
                shortTitle: "Temperatura",
                unit: temperature?.unit ?? "°C",
                values: historianSeries(pointsByKey[temperature?.key ?? ""]),
                accent: "amber" as Accent,
            },
            {
                key: HISTORY_KEYS.humidity,
                title: "Humidade (%)",
                shortTitle: "Humidade",
                unit: humidity?.unit ?? "%",
                values: historianSeries(pointsByKey[humidity?.key ?? ""]),
                accent: "blue" as Accent,
            },
            {
                key: HISTORY_KEYS.windSpeed,
                title: "Vento (km/h)",
                shortTitle: "Vento",
                unit: windSpeed?.unit ?? "km/h",
                values: historianSeries(pointsByKey[windSpeed?.key ?? ""]),
                accent: "emerald" as Accent,
            },
            {
                key: HISTORY_KEYS.radiation,
                title: "Radiação (W/m²)",
                shortTitle: "Radiação",
                unit: radiation?.unit ?? "W/m²",
                values: historianSeries(pointsByKey[radiation?.key ?? ""]),
                accent: "violet" as Accent,
            },
        ],
        [
            pointsByKey,
            humidity?.key,
            humidity?.unit,
            radiation?.key,
            radiation?.unit,
            temperature?.key,
            temperature?.unit,
            windSpeed?.key,
            windSpeed?.unit,
        ],
    );

    const windDirectionHistory = useMemo(
        () => historianSeries(pointsByKey[windDirection?.key ?? ""]),
        [pointsByKey, windDirection?.key],
    );

    return (
        <div className="space-y-4 pb-4">
            <WeatherHeroPanel
                theme={theme}
                forecast={forecast}
                selectedDay={selectedForecastDay}
                selectedDayIndex={selectedForecastDayIndex}
                loading={weatherForecast.loading}
                error={weatherForecast.error}
            />

            <ForecastPanel
                theme={theme}
                forecast={forecast}
                loading={weatherForecast.loading}
                error={weatherForecast.error}
                selectedIndex={selectedForecastDayIndex}
                onSelectDay={setSelectedForecastDayIndex}
            />

            <div className="grid items-stretch gap-4 xl:grid-cols-[minmax(330px,0.82fr)_minmax(330px,0.82fr)_minmax(620px,1.55fr)]">
                <WeatherSummaryPanel
                    theme={theme}
                    temperature={currentTemperature}
                    humidity={currentHumidity}
                    windSpeed={currentWindSpeed}
                    dewPoint={currentDewPoint}
                    radiation={currentRadiation}
                    temperatureUnit={temperature?.unit ?? "°C"}
                    humidityUnit={humidity?.unit ?? "%"}
                    windUnit={windSpeed?.unit ?? "km/h"}
                    radiationUnit={radiation?.unit ?? "W/m²"}
                />

                <WindDirectionPanel
                    theme={theme}
                    direction={currentWindDirection}
                    history={windDirectionHistory}
                    windHistory={historianSeries(
                        pointsByKey[windSpeed?.key ?? ""]
                    )}
                />

                <RealtimeChartPanel
                    theme={theme}
                    series={chartSeries}
                    historyLoading={historyLoading}
                    hours={HISTORY_HOURS}
                />
            </div>
        </div>
    );
}

function WeatherHeroPanel({
    theme,
    forecast,
    selectedDay,
    selectedDayIndex,
    loading,
    error,
}: {
    theme: "dark" | "light";
    forecast: WeatherForecastResponse | null;
    selectedDay: WeatherForecastResponse["daily"][number] | null;
    selectedDayIndex: number;
    loading: boolean;
    error: string | null;
}) {
    const isDark = theme === "dark";
    const day = selectedDay ?? forecast?.daily?.[0];

    if (!day) {
        return <HeroState>Sem previsão disponível.</HeroState>;
    }

    const location = forecast
        ? `${forecast.location.name}, ${forecast.location.country}`
        : "Mira, Portugal";
    const conditionText = day.condition?.text ?? "--";
    const heroBackground = weatherBackgroundForCondition(conditionText);
    const heroTemperature = day.maxTemperatureC ?? null;
    const heroMinTemperature = day.minTemperatureC ?? null;
    const heroDateLabel =
        selectedDayIndex === 0
            ? "Hoje"
            : selectedDayIndex === 1
                ? "Amanhã"
                : weekday(day.date);

    return (
        <section
            className={
                isDark
                    ? `${RADIUS} relative overflow-hidden border border-sky-400/15 bg-[#071421] shadow-[0_18px_46px_rgba(0,0,0,0.24)]`
                    : `${RADIUS} relative overflow-hidden border border-slate-200 bg-white shadow-[0_16px_38px_rgba(15,23,42,0.08)]`
            }
        >
            <img
                src={heroBackground}
                alt=""
                className="absolute inset-0 h-full w-full object-cover opacity-75"
                style={{ objectPosition: "center 20%" }}
            />
            <div className="absolute inset-0 bg-[linear-gradient(90deg,rgba(4,13,24,0.98)_0%,rgba(5,17,31,0.94)_32%,rgba(7,20,33,0.72)_58%,rgba(7,20,33,0.42)_100%)]" />
            <div className="absolute inset-0 bg-[radial-gradient(circle_at_82%_18%,rgba(251,191,36,0.18),transparent_24%)]" />

            <div className="relative p-5 lg:p-6">
                <div className="flex flex-wrap items-start justify-between gap-4">
                    <div>
                        <h2 className="text-xl font-black tracking-[-0.04em] text-white">
                            {location}
                        </h2>
                        <p className="mt-1 text-sm font-medium text-slate-300">
                            {selectedDayIndex === 0
                                ? "Condições de hoje"
                                : `Previsão para ${heroDateLabel}`}
                        </p>
                    </div>

                    <button
                        type="button"
                        className="inline-flex items-center gap-2 rounded-[5px] border border-sky-400/25 bg-sky-400/10 px-3 py-2 text-sm font-black text-sky-200 transition hover:bg-sky-400/15"
                    >
                        <Activity className="h-4 w-4" />
                        Ver quadro legado
                    </button>
                </div>

                {loading ? (
                    <HeroState>A carregar meteorologia...</HeroState>
                ) : error ? (
                    <HeroState>{error}</HeroState>
                ) : (
                    <div className="mt-7 grid gap-5 xl:grid-cols-[260px_1fr]">
                        <div className="flex items-center gap-5">
                            {day.condition?.icon ? (
                                <img
                                    src={day.condition.icon}
                                    alt={day.condition.text}
                                    className="h-20 w-20 shrink-0 drop-shadow-[0_0_22px_rgba(250,204,21,0.35)]"
                                />
                            ) : (
                                <Sun className="h-20 w-20 shrink-0 fill-yellow-300 text-yellow-300 drop-shadow-[0_0_22px_rgba(250,204,21,0.35)]" />
                            )}

                            <div>
                                <div className="text-[48px] font-black leading-none tracking-[-0.07em] text-white">
                                    {formatNumber(heroTemperature, 1)}°
                                </div>
                                <p className="mt-2 text-sm font-black text-white">
                                    {conditionText}
                                </p>
                                <p className="mt-1 text-xs font-semibold text-slate-400">
                                    {heroMinTemperature !== null
                                        ? `Mínima ${formatNumber(heroMinTemperature, 0)}°`
                                        : "Sem mínima disponível"}
                                </p>
                            </div>
                        </div>

                        <div className="grid gap-0 divide-y divide-white/10 rounded-[5px] border border-white/0 sm:grid-cols-2 sm:divide-x sm:divide-y-0 lg:grid-cols-5">
                            <HeroMetric
                                title="Chuva"
                                value={`${day.dailyRainChance ?? "--"}%`}
                                helper={`${formatNumber(day.totalPrecipitationMm, 1)} mm previstos`}
                                icon={CloudRain}
                            />

                            <HeroMetric
                                title="UV Index"
                                value={formatNumber(day.uv, 0)}
                                helper={uvLabel(day.uv)}
                                icon={Sun}
                            />

                            <HeroMetric
                                title="Vento"
                                value={`${formatNumber(day.averageWindKph, 1)} km/h`}
                                helper={
                                    day.averageWindDirection
                                        ? `Direção média · ${day.averageWindDirection}`
                                        : "--"
                                }
                                icon={Wind}
                            />

                            <HeroMetric
                                title="Humidade"
                                value={`${formatNumber(day.averageHumidity, 0)}%`}
                                helper="Média diária"
                                icon={Droplets}
                            />

                            <HeroMetric
                                title="Visibilidade"
                                value={`${formatNumber(day.averageVisibilityKm, 1)} km`}
                                helper="Média diária"
                                icon={Eye}
                            />
                        </div>
                    </div>
                )}
            </div>
        </section>
    );
}

function ForecastPanel({
    theme,
    forecast,
    loading,
    error,
    selectedIndex,
    onSelectDay,
}: {
    theme: "dark" | "light";
    forecast: WeatherForecastResponse | null;
    loading: boolean;
    error: string | null;
    selectedIndex: number;
    onSelectDay: (index: number) => void;
}) {
    const isDark = theme === "dark";
    const days = forecast?.daily?.slice(0, 7) ?? [];
    const selectedDay = days[selectedIndex] ?? days[0] ?? null;

    return (
        <section className={panelClass(isDark)}>
            <div className="mb-4 flex flex-wrap items-end justify-between gap-3">
                <div>
                    <h2 className={panelTitleClass(isDark)}>Previsão diária</h2>
                    <p className="mt-1 text-sm text-slate-400">Próximos 7 dias</p>
                </div>

                {selectedDay && (
                    <div className="hidden text-right lg:block">
                        <p className="text-xs font-bold uppercase tracking-[0.18em] text-slate-500">
                            Dia selecionado
                        </p>
                        <p className="mt-1 text-sm font-black text-slate-200">
                            {weekday(selectedDay.date)} · {shortDate(selectedDay.date)}
                        </p>
                    </div>
                )}
            </div>

            {loading ? (
                <PanelState theme={theme}>A carregar previsão...</PanelState>
            ) : error ? (
                <PanelState theme={theme}>{error}</PanelState>
            ) : !days.length ? (
                <PanelState theme={theme}>Sem previsão diária disponível.</PanelState>
            ) : (
                <div className="grid gap-2 md:grid-cols-2 xl:grid-cols-7">
                    {days.map((day, index) => (
                        <ForecastDayCard
                            key={day.date}
                            theme={theme}
                            day={day}
                            index={index}
                            active={index === selectedIndex}
                            onClick={() => onSelectDay(index)}
                        />
                    ))}
                </div>
            )}
        </section>
    );
}

function ForecastDayCard({
    theme,
    day,
    index,
    active,
    onClick,
}: {
    theme: "dark" | "light";
    day: WeatherForecastResponse["daily"][number];
    index: number;
    active: boolean;
    onClick: () => void;
}) {
    const isDark = theme === "dark";
    const label = index === 0 ? "Hoje" : index === 1 ? "Amanhã" : weekday(day.date);
    const conditionText = day.condition?.text ?? "";
    const background = weatherBackgroundForCondition(conditionText);

    return (
        <button
            type="button"
            onClick={onClick}
            className={[
                RADIUS,
                "group relative min-h-[110px] overflow-hidden px-3.5 py-3 text-left outline-none transition-all duration-300 focus-visible:ring-1 focus-visible:ring-sky-300/45",
                active
                    ? isDark
                        ? "bg-white/[0.04]"
                        : "bg-slate-100"
                    : isDark
                        ? "bg-white/[0.015] hover:bg-white/[0.035]"
                        : "bg-slate-100/60 hover:bg-slate-100",
            ].join(" ")}
            style={{
                backgroundImage: `
                    linear-gradient(
                        180deg,
                        rgba(4,13,24,${active ? "0.78" : "0.86"}),
                        rgba(4,13,24,${active ? "0.95" : "0.985"})
                    ),
                    url(${background})
                `,
                backgroundSize: "cover",
                backgroundPosition: "center 24%",
            }}
        >
            <span
                className={[
                    "pointer-events-none absolute inset-0 transition-colors duration-300",
                    active
                        ? "bg-white/[0.015]"
                        : "bg-[#071421]/35 group-hover:bg-[#071421]/24",
                ].join(" ")}
            />

            <span
                className={[
                    "pointer-events-none absolute inset-0 backdrop-blur-[2px] transition-opacity duration-300",
                    active ? "opacity-45" : "opacity-75 group-hover:opacity-60",
                ].join(" ")}
            />

            <span className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/14 to-transparent" />

            <span
                className={[
                    "pointer-events-none absolute inset-0 rounded-[inherit] transition-opacity duration-300",
                    active
                        ? "shadow-[inset_0_0_0_1px_rgba(255,255,255,0.08),inset_0_1px_0_rgba(255,255,255,0.10)]"
                        : "shadow-[inset_0_0_0_1px_rgba(255,255,255,0.035),inset_0_1px_0_rgba(255,255,255,0.06)]",
                ].join(" ")}
            />

            {active && (
                <span className="pointer-events-none absolute left-4 right-4 top-0 h-px bg-white/55" />
            )}

            <span className="relative z-10 flex h-full flex-col justify-between">
                <span className="flex items-start justify-between gap-3">
                    <span>
                        <span className="block text-sm font-black text-white">
                            {label}
                        </span>
                        <span className="mt-1 block text-xs font-semibold text-slate-300">
                            {shortDate(day.date)}
                        </span>
                    </span>

                    {day.condition?.icon ? (
                        <img
                            src={day.condition.icon}
                            alt={day.condition.text}
                            className={[
                                "h-9 w-9 shrink-0 transition duration-300",
                                active
                                    ? "opacity-95 drop-shadow-[0_0_10px_rgba(250,204,21,0.20)]"
                                    : "opacity-75 drop-shadow-[0_0_8px_rgba(250,204,21,0.14)] group-hover:opacity-90",
                            ].join(" ")}
                        />
                    ) : (
                        <Cloud className="h-9 w-9 shrink-0 text-slate-300" />
                    )}
                </span>

                <span className="flex items-end justify-between gap-3">
                    <span className="flex items-end gap-2">
                        <span className="text-2xl font-black leading-none tracking-[-0.06em] text-white">
                            {Math.round(day.maxTemperatureC)}°
                        </span>
                        <span className="mb-0.5 text-sm font-black text-slate-400">
                            {Math.round(day.minTemperatureC)}°
                        </span>
                    </span>

                    <span
                        className={[
                            "rounded-full px-2 py-1 text-[10px] font-black uppercase tracking-[0.08em] backdrop-blur-sm transition",
                            active
                                ? "border border-white/10 bg-white/[0.065] text-white"
                                : "border border-white/10 bg-white/[0.045] text-slate-400 group-hover:text-slate-300",
                        ].join(" ")}
                    >
                        UV {formatNumber(day.uv, 0)}
                    </span>
                </span>
            </span>
        </button>
    );
}

function WeatherSummaryPanel({
    theme,
    temperature,
    humidity,
    windSpeed,
    dewPoint,
    temperatureUnit,
    humidityUnit,
    windUnit,
    radiation,
    radiationUnit
}: {
    theme: "dark" | "light";
    temperature: number | null;
    humidity: number | null;
    windSpeed: number | null;
    dewPoint: number | null;
    temperatureUnit: string;
    humidityUnit: string;
    windUnit: string;
    radiation: number | null;
    radiationUnit: string;
}) {
    const isDark = theme === "dark";

    return (
        <section className={panelClass(isDark)}>
            <h2 className={panelTitleClass(isDark)}>Resumo meteorológico</h2>

            <div className="mt-3 grid flex-1 content-start gap-2">
                <SummaryTile
                    theme={theme}
                    icon={Thermometer}
                    accent="amber"
                    label="Temperatura"
                    value={`${formatNumber(temperature, 1)}${temperatureUnit}`}
                    badge={temperatureBadge(temperature)}
                />
                <SummaryTile
                    theme={theme}
                    icon={Wind}
                    accent="cyan"
                    label="Vento"
                    value={`${formatNumber(windSpeed, 0)} ${windUnit}`}
                    badge={windBadge(windSpeed)}
                />
                <SummaryTile
                    theme={theme}
                    icon={Droplets}
                    accent="blue"
                    label="Humidade"
                    value={`${formatNumber(humidity, 0)}${humidityUnit}`}
                    badge={humidityBadge(humidity)}
                />
                <SummaryTile
                    theme={theme}
                    icon={Activity}
                    accent="emerald"
                    label="Ponto de orvalho"
                    value={`${formatNumber(dewPoint, 1)}°C`}
                    badge="Elevado"
                />
                <SummaryTile
                    theme={theme}
                    icon={Zap}
                    accent="violet"
                    label="Radiação"
                    value={`${formatNumber(radiation, 0)} ${radiationUnit}`}
                    badge={radiationBadge(radiation)}
                />
            </div>
        </section>
    );
}

function radiationBadge(value: number | null) {
    if (value === null) return "Sem dados";
    if (value >= 800) return "Alta";
    if (value >= 400) return "Média";
    return "Baixa";
}

function WindDirectionPanel({
    theme,
    direction,
    history,
    windHistory,
}: {
    theme: "dark" | "light";
    direction: number | null;
    history: Array<{
        timestamp: string;
        value: number;
    }>;
    windHistory: Array<{
        timestamp: string;
        value: number;
    }>;
}) {
    const isDark = theme === "dark";
    const angle = direction ?? 0;
    const cardinal = directionName(direction);
    const degrees = direction !== null ? Math.round(direction) : null;
    const previousDirection =
        history.length > 0
            ? directionName(history[history.length - 1].value)
            : "--";

    const currentDirection = directionName(direction);

    const directionTrend =
        previousDirection === currentDirection
            ? currentDirection
            : `${previousDirection} → ${currentDirection}`;
    const maxGust =
        windHistory.length > 0
            ? Math.max(...windHistory.map((point) => point.value))
            : null;

    const consistency = windConsistency(history);

    return (
        <section className={panelClass(isDark)}>
            <h2 className={panelTitleClass(isDark)}>Direção do vento</h2>

            <div className="mt-2 flex flex-1 items-center justify-center">
                <div className="relative h-[250px] w-[250px]">
                    <div className={isDark ? "absolute inset-0 rounded-full border border-white/10 bg-[#0b1220]" : "absolute inset-0 rounded-full border border-slate-200 bg-slate-50"} />
                    <div className={isDark ? "absolute inset-6 rounded-full border border-white/10" : "absolute inset-6 rounded-full border border-slate-200"} />
                    <div className={isDark ? "absolute inset-[74px] rounded-full border border-white/10 bg-white/[0.02]" : "absolute inset-[74px] rounded-full border border-slate-200 bg-white"} />

                    {Array.from({ length: 48 }).map((_, index) => {
                        const major = index % 6 === 0;
                        return (
                            <span
                                key={index}
                                className={`absolute left-1/2 top-1/2 w-px origin-[50%_116px] ${major ? "h-3" : "h-1.5"} ${isDark ? "bg-slate-600/60" : "bg-slate-300"}`}
                                style={{
                                    transform: `translate(-50%, -116px) rotate(${index * 7.5}deg)`,
                                }}
                            />
                        );
                    })}

                    <CompassLabel label="N" isDark={isDark} className="left-1/2 top-[14px] -translate-x-1/2" />
                    <CompassLabel label="S" isDark={isDark} className="bottom-[14px] left-1/2 -translate-x-1/2" />
                    <CompassLabel label="W" isDark={isDark} className="left-[16px] top-1/2 -translate-y-1/2" />
                    <CompassLabel label="E" isDark={isDark} className="right-[16px] top-1/2 -translate-y-1/2" />
                    <CompassLabel label="NW" isDark={isDark} className="left-[50px] top-[50px]" />
                    <CompassLabel label="NE" isDark={isDark} className="right-[50px] top-[50px]" />
                    <CompassLabel label="SW" isDark={isDark} className="bottom-[50px] left-[50px]" />
                    <CompassLabel label="SE" isDark={isDark} className="bottom-[50px] right-[50px]" />

                    <div className="absolute inset-0 flex items-center justify-center">
                        <div className="relative h-24 w-24">
                            <div
                                className="absolute left-1/2 top-1/2 h-[112px] w-[46px] origin-bottom rounded-t-full bg-gradient-to-b from-sky-400 to-blue-700/20"
                                style={{
                                    clipPath: "polygon(50% 0%, 100% 100%, 50% 82%, 0% 100%)",
                                    transform: `translate(-50%, -100%) rotate(${angle}deg)`,
                                }}
                            />
                            <div className={isDark ? "absolute left-1/2 top-1/2 h-24 w-24 -translate-x-1/2 -translate-y-1/2 rounded-full border border-white/10 bg-[#0b1220]" : "absolute left-1/2 top-1/2 h-24 w-24 -translate-x-1/2 -translate-y-1/2 rounded-full border border-slate-200 bg-white"} />
                            <div className="absolute inset-0 flex flex-col items-center justify-center">
                                <span className={isDark ? "text-4xl font-black text-slate-100" : "text-4xl font-black text-slate-950"}>
                                    {cardinal}
                                </span>
                                <span className="text-xs font-black text-slate-500">
                                    {degrees ?? "--"}°
                                </span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div className="mt-2 grid grid-cols-3 gap-2">
                <SmallStat
                    theme={theme}
                    label="Rajada máx."
                    value={maxGust !== null ? `${Math.round(maxGust)} km/h` : "--"}
                />
                <SmallStat
                    theme={theme}
                    label="Direção"
                    value={directionTrend}
                />
                <SmallStat
                    theme={theme}
                    label="Constância"
                    value={consistency}
                />
            </div>
        </section>
    );
}

function windConsistency(
    history: Array<{ timestamp: string; value: number }>
) {
    if (history.length < 2) return "--";

    let totalVariation = 0;

    for (let i = 1; i < history.length; i++) {
        const previous = history[i - 1].value;
        const current = history[i].value;

        let delta = Math.abs(current - previous);

        if (delta > 180) {
            delta = 360 - delta;
        }

        totalVariation += delta;
    }

    const averageVariation = totalVariation / (history.length - 1);

    if (averageVariation <= 5) return "Muito estável";
    if (averageVariation <= 15) return "Estável";
    if (averageVariation <= 35) return "Variável";

    return "Instável";
}

function RealtimeChartPanel({
    theme,
    series,
    historyLoading,
}: {
    theme: "dark" | "light";
    series: ChartSeries[];
    historyLoading: boolean;
    hours: number;
}) {
    const [mode, setMode] = useState<WorkspaceChartMode>("line");
    const [timeRange, setTimeRange] = useState<WorkspaceChartTimeRange>("6h");
    const [interval, setInterval] = useState<WorkspaceChartInterval>("5m");
    const [visibleKeys, setVisibleKeys] = useState<HistoryKey[]>([
        HISTORY_KEYS.temperature,
        HISTORY_KEYS.humidity,
    ]);

    const chart: WorkspaceChartConfig = {
        id: "meteo-realtime",
        title: "Gráficos em tempo real",
        subtitle: "Leituras históricas da estação meteorológica",
        icon: Activity,
        status: "online",
        sourceLabel: "Estação",
        mode,
        timeRange,
        interval,
        variables: series.map((item) => ({
            key: item.key,
            label: item.shortTitle,
            unit: item.unit,
            color: chartColor(item.accent),
            visible: visibleKeys.includes(item.key),
            data: item.values.map((point) => ({
                timestamp: point.timestamp,
                value: point.value,
            })),
        })),
    };

    function handleVariableToggle(variableKey: string) {
        const key = variableKey as HistoryKey;

        setVisibleKeys((current) => {
            if (current.includes(key)) {
                return current.length <= 1
                    ? current
                    : current.filter((item) => item !== key);
            }

            return [...current, key];
        });
    }

    return (
        <div className="relative flex min-h-0 flex-1 flex-col">
            <div className="absolute right-3 top-3 z-20">
                <button
                    type="button"
                    className="rounded-[5px] border border-sky-400/20 bg-sky-400/10 px-3 py-2 text-xs font-black text-sky-200 transition hover:bg-sky-400/15"
                >
                    Gráficos Personalizados
                </button>
            </div>

            <CompactMeteoChart>
                <WorkspaceChart
                    theme={theme}
                    chart={chart}
                    loading={historyLoading}
                    configuredVariableCount={series.length}
                    onModeChange={setMode}
                    onVariableToggle={handleVariableToggle}
                    onTimeRangeChange={setTimeRange}
                    onIntervalChange={setInterval}
                />
            </CompactMeteoChart>
        </div>
    );
}

function chartColor(accent: Accent) {
    switch (accent) {
        case "amber":
            return "#facc15";
        case "blue":
            return "#38bdf8";
        case "cyan":
            return "#67e8f9";
        case "emerald":
            return "#34d399";
        case "violet":
            return "#a78bfa";
    }
}

function CompactMeteoChart({
    children,
}: {
    children: React.ReactNode;
}) {
    return (
        <div className="h-full [&>section]:h-full [&>section>header]:px-4 [&>section>header]:py-3 [&>section>main]:px-3 [&>section>main]:pb-3 [&_main_section>div.relative]:h-[235px] [&_main_section>div.relative]:min-h-[235px]">
            {children}
        </div>
    );
}

function HeroMetric({
    title,
    value,
    helper,
    icon: Icon,
}: {
    title: string;
    value: string;
    helper: string;
    icon: LucideIcon;
}) {
    return (
        <div className="px-4 py-3">
            <div className="flex items-center gap-2 text-xs font-semibold text-slate-400">
                <Icon className="h-3.5 w-3.5" />
                {title}
            </div>
            <p className="mt-3 text-base font-black text-white">{value}</p>
            <p className="mt-2 text-xs font-medium text-slate-400">{helper}</p>
        </div>
    );
}

function SummaryTile({
    theme,
    icon: Icon,
    accent,
    label,
    value,
    badge,
}: {
    theme: "dark" | "light";
    icon: LucideIcon;
    accent: Accent;
    label: string;
    value: string;
    badge: string;
}) {
    const isDark = theme === "dark";
    const colors = accentColors(accent);

    return (
        <article
            className={
                isDark
                    ? `${RADIUS} grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-1 border border-white/10 bg-white/[0.03] px-3.5 py-3`
                    : `${RADIUS} grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-1 border border-slate-200 bg-slate-50 px-3.5 py-3`
            }
        >
            <div className="flex min-w-0 items-center gap-2.5">
                <Icon className={`h-5 w-5 shrink-0 ${colors.text}`} />
                <p
                    className={
                        isDark
                            ? "truncate text-sm font-semibold text-slate-300"
                            : "truncate text-sm font-semibold text-slate-600"
                    }
                >
                    {label}
                </p>
            </div>

            <p
                className={
                    isDark
                        ? "text-[22px] font-black leading-none tracking-[-0.04em] text-slate-100"
                        : "text-[22px] font-black leading-none tracking-[-0.04em] text-slate-950"
                }
            >
                {value}
            </p>

            <div className="col-span-2 flex items-center gap-2 pl-7">
                <span
                    className={
                        isDark
                            ? "rounded-[5px] bg-slate-700 px-2 py-1 text-[11px] font-black text-slate-200"
                            : "rounded-[5px] bg-white px-2 py-1 text-[11px] font-black text-slate-700"
                    }
                >
                    {badge}
                </span>
            </div>
        </article>
    );
}
function SmallStat({
    theme,
    label,
    value,
}: {
    theme: "dark" | "light";
    label: string;
    value: string;
}) {
    const isDark = theme === "dark";

    return (
        <div
            className={
                isDark
                    ? `${RADIUS} border border-white/10 bg-white/[0.03] px-2 py-2.5 text-center`
                    : `${RADIUS} border border-slate-200 bg-slate-50 px-2 py-2.5 text-center`
            }
        >
            <p className="text-[10px] font-bold text-slate-500">{label}</p>
            <p
                className={
                    isDark
                        ? "mt-1 text-sm font-black text-slate-100"
                        : "mt-1 text-sm font-black text-slate-950"
                }
            >
                {value}
            </p>
        </div>
    );
}


function CompassLabel({
    label,
    className,
    isDark,
}: {
    label: string;
    className: string;
    isDark: boolean;
}) {
    return (
        <span
            className={`absolute flex h-6 min-w-6 items-center justify-center rounded-full px-1 text-[12px] font-black leading-none ${isDark ? "text-slate-300" : "text-slate-500"
                } ${className}`}
        >
            {label}
        </span>
    );
}

function PanelState({
    theme,
    children,
}: {
    theme: "dark" | "light";
    children: string;
}) {
    const isDark = theme === "dark";
    return (
        <div
            className={
                isDark
                    ? `${RADIUS} border border-white/10 bg-white/[0.03] p-5 text-sm text-slate-400`
                    : `${RADIUS} border border-slate-200 bg-slate-50 p-5 text-sm text-slate-500`
            }
        >
            {children}
        </div>
    );
}

function HeroState({ children }: { children: string }) {
    return (
        <div className="mt-7 rounded-[5px] border border-white/10 bg-white/[0.03] p-5 text-sm font-semibold text-slate-300">
            {children}
        </div>
    );
}

function panelClass(isDark: boolean) {
    return isDark
        ? `${RADIUS} flex h-full flex-col border border-white/10 bg-[#071421] p-3 shadow-[0_14px_34px_rgba(0,0,0,0.22)]`
        : `${RADIUS} flex h-full flex-col border border-slate-200 bg-white p-3 shadow-[0_10px_26px_rgba(15,23,42,0.06)]`;
}

function panelTitleClass(isDark: boolean) {
    return isDark
        ? "text-base font-black text-slate-100"
        : "text-base font-black text-slate-950";
}

function calculateDewPoint(
    temperature: number | null,
    humidity: number | null,
) {
    if (temperature === null || humidity === null || humidity <= 0) return null;
    return temperature - (100 - humidity) / 5;
}

function historianSeries(points: HistorianPoint[] | undefined) {
    return (points ?? [])
        .filter(
            (point): point is HistorianPoint & { numericValue: number } =>
                point.numericValue !== null,
        )
        .map((point) => ({
            timestamp: point.timestamp,
            value: point.numericValue,
        }));
}

function weatherBackgroundForCondition(condition: string | null | undefined) {
    const normalized = normalizeWeatherCondition(condition);

    if (!normalized) return sunnyBackground;

    if (
        normalized.includes("thunder") ||
        normalized.includes("trovoada") ||
        normalized.includes("relampago") ||
        normalized.includes("storm")
    ) {
        return thunderstormBackground;
    }

    if (
        normalized.includes("snowstorm") ||
        normalized.includes("blizzard") ||
        normalized.includes("heavy snow") ||
        normalized.includes("neve forte") ||
        normalized.includes("tempestade de neve")
    ) {
        return snowstormBackground;
    }

    if (normalized.includes("snow") || normalized.includes("neve")) {
        return snowBackground;
    }

    if (
        normalized.includes("patchy rain") ||
        normalized.includes("rain nearby") ||
        normalized.includes("possibilidade de chuva") ||
        normalized.includes("aguaceiros fracos")
    ) {
        return patchyRainBackground;
    }

    if (
        normalized.includes("rain") ||
        normalized.includes("chuva") ||
        normalized.includes("aguaceiro") ||
        normalized.includes("drizzle") ||
        normalized.includes("chuvisco")
    ) {
        return rainyBackground;
    }

    if (
        normalized.includes("fog") ||
        normalized.includes("mist") ||
        normalized.includes("nevoeiro") ||
        normalized.includes("neblina")
    ) {
        return foggyBackground;
    }

    if (normalized.includes("overcast") || normalized.includes("encoberto")) {
        return overcastBackground;
    }

    if (
        normalized.includes("partly cloudy") ||
        normalized.includes("parcialmente nublado") ||
        normalized.includes("partly") ||
        normalized.includes("parcialmente")
    ) {
        return partlyCloudyBackground;
    }

    if (normalized.includes("cloudy") || normalized.includes("nublado")) {
        return cloudyBackground;
    }

    return sunnyBackground;
}

function normalizeWeatherCondition(condition: string | null | undefined) {
    return (condition ?? "")
        .normalize("NFD")
        .replace(/[\u0300-\u036f]/g, "")
        .toLowerCase();
}

function formatNumber(value: number | null | undefined, decimals = 0) {
    if (value === null || value === undefined || Number.isNaN(value)) return "--";
    return Number.isInteger(value) || decimals === 0
        ? String(Math.round(value))
        : value.toFixed(decimals);
}

function directionName(direction: number | null) {
    if (direction === null) return "--";

    const labels = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"];
    const index = Math.round(direction / 45) % 8;

    return labels[index];
}

function weekday(date: string) {
    return new Date(date)
        .toLocaleDateString("pt-PT", { weekday: "long" })
        .replace(/^./, (letter) => letter.toUpperCase());
}

function shortDate(date: string) {
    return new Date(date)
        .toLocaleDateString("pt-PT", { day: "2-digit", month: "short" })
        .replace(".", "");
}

function temperatureBadge(value: number | null) {
    if (value === null) return "Sem dados";
    if (value >= 30) return "Quente";
    if (value <= 10) return "Frio";
    return "Normal";
}

function humidityBadge(value: number | null) {
    if (value === null) return "Sem dados";
    if (value >= 80) return "Alta";
    if (value <= 35) return "Baixa";
    return "Normal";
}

function windBadge(value: number | null) {
    if (value === null) return "Sem dados";
    if (value >= 30) return "Forte";
    if (value >= 10) return "Moderado";
    return "Fraco";
}

function uvLabel(value: number | null | undefined) {
    if (value === null || value === undefined) return "--";
    if (value >= 11) return "Extremo";
    if (value >= 8) return "Muito elevado";
    if (value >= 6) return "Elevado";
    if (value >= 3) return "Moderado";
    return "Baixo";
}

function accentColors(accent: Accent) {
    switch (accent) {
        case "amber":
            return {
                text: "text-amber-300",
                stroke: "stroke-amber-300",
                fill: "fill-amber-300",
                bg: "bg-amber-300",
            };
        case "blue":
            return {
                text: "text-sky-400",
                stroke: "stroke-sky-400",
                fill: "fill-sky-400",
                bg: "bg-sky-400",
            };
        case "cyan":
            return {
                text: "text-cyan-300",
                stroke: "stroke-cyan-300",
                fill: "fill-cyan-300",
                bg: "bg-cyan-300",
            };
        case "emerald":
            return {
                text: "text-emerald-400",
                stroke: "stroke-emerald-400",
                fill: "fill-emerald-400",
                bg: "bg-emerald-400",
            };
        case "violet":
            return {
                text: "text-violet-400",
                stroke: "stroke-violet-400",
                fill: "fill-violet-400",
                bg: "bg-violet-400",
            };
    }
}