import { useMemo, useState } from "react";
import {
    Activity,
    Loader2,
    ChevronDown,
    Download,
    Maximize2,
    Save,
    Settings2,
    SlidersHorizontal,
    type LucideIcon,
} from "lucide-react";
import {
    Area,
    AreaChart,
    Bar,
    BarChart,
    CartesianGrid,
    Line,
    LineChart,
    ReferenceLine,
    ResponsiveContainer,
    Tooltip,
    XAxis,
    YAxis,
} from "recharts";

import { displayUnit } from "../../shared/utils/displayUnit";
export type WorkspaceChartMode = "line" | "area" | "bar";

export type WorkspaceChartTimeRange = "15m" | "1h" | "6h" | "24h" | "7d" | "30d";

export type WorkspaceChartInterval = "1m" | "5m" | "15m" | "1h";

export type WorkspaceChartPoint = {
    timestamp: string;
    value: number | null;
};

export type WorkspaceChartVariable = {
    key: string;
    label: string;
    unit?: string;
    color: string;
    data: WorkspaceChartPoint[];
    visible: boolean;
    limit?: number;
};

export type WorkspaceChartConfig = {
    id: string;
    title: string;
    subtitle: string;
    icon: LucideIcon;
    status?: "online" | "offline";
    sourceLabel?: string;
    mode: WorkspaceChartMode;
    timeRange: WorkspaceChartTimeRange;
    interval: WorkspaceChartInterval;
    variables: WorkspaceChartVariable[];
};

type Props = {
    theme: "dark" | "light";
    chart: WorkspaceChartConfig;
    detached?: boolean;
    dragHandle?: React.ReactNode;
    onHeaderPointerDown?: (event: React.PointerEvent) => void;
    onModeChange: (mode: WorkspaceChartMode) => void;
    onVariableToggle: (variableKey: string) => void;
    onTimeRangeChange: (range: WorkspaceChartTimeRange) => void;
    onIntervalChange: (interval: WorkspaceChartInterval) => void;
    onSave?: () => void;
    onExport?: () => void;
    onDetach?: () => void;
    onAttach?: () => void;
    loading?: boolean;
    configuredVariableCount?: number;
};

type ChartRow = {
    time: string;
    timestamp: string;
    timestampMs: number;
    [key: string]: string | number | null | undefined;
};

type YAxisConfig = {
    id: string;
    unit: string;
    orientation: "left" | "right";
    color: string;
};

const RADIUS = "rounded-[8px]";

const RANGE_OPTIONS: { value: WorkspaceChartTimeRange; label: string }[] = [
    { value: "15m", label: "15M" },
    { value: "1h", label: "1H" },
    { value: "6h", label: "6H" },
    { value: "24h", label: "24H" },
    { value: "7d", label: "7D" },
    { value: "30d", label: "30D" },
];

const INTERVAL_OPTIONS: { value: WorkspaceChartInterval; label: string }[] = [
    { value: "1m", label: "1m" },
    { value: "5m", label: "5m" },
    { value: "15m", label: "15m" },
    { value: "1h", label: "1h" },
];

export function WorkspaceChart({
    theme,
    chart,
    loading = false,
    detached = false,
    dragHandle,
    onHeaderPointerDown,
    onModeChange,
    onVariableToggle,
    onTimeRangeChange,
    onIntervalChange,
    onSave,
    onExport,
    onDetach,
    onAttach,
    configuredVariableCount = chart.variables.length
}: Props) {
    const isDark = theme === "dark";

    const [rangeMenuOpen, setRangeMenuOpen] = useState(false);
    const [intervalMenuOpen, setIntervalMenuOpen] = useState(false);
    const [modeMenuOpen, setModeMenuOpen] = useState(false);
    const [variableMenuOpen, setVariableMenuOpen] = useState(false);
    const [showIndicators, setShowIndicators] = useState(true);
    const [zeroBaseline, setZeroBaseline] = useState(false);

    const visibleVariables = useMemo(
        () => chart.variables.filter((variable) => variable.visible),
        [chart.variables],
    );

    const hasConfiguredVariables = configuredVariableCount > 0;
    const shouldShowLoading = loading && hasConfiguredVariables;

    const primaryVariable = visibleVariables[0] ?? null;

    const yAxes = useMemo(
        () => buildYAxisConfigs(visibleVariables),
        [visibleVariables],
    );

    const data = useMemo<ChartRow[]>(() => {
        const fromTime = Date.now() - rangeToMs(chart.timeRange);
        const bucketMs = intervalToMs(chart.interval);

        const buckets = new Map<
            number,
            {
                timestamp: string;
                values: Record<string, number[]>;
            }
        >();

        for (const variable of chart.variables) {
            for (const point of variable.data) {

                if (point.value === null) {
                    continue;
                }
                const pointTime = new Date(point.timestamp).getTime();

                if (!Number.isFinite(pointTime) || pointTime < fromTime) {
                    continue;
                }

                const bucketTime =
                    bucketMs === 0
                        ? pointTime
                        : Math.floor(pointTime / bucketMs) * bucketMs;

                const existing = buckets.get(bucketTime);

                if (existing) {
                    existing.values[variable.key] ??= [];
                    existing.values[variable.key].push(point.value);
                } else {
                    buckets.set(bucketTime, {
                        timestamp: new Date(bucketTime).toISOString(),
                        values: {
                            [variable.key]: [point.value],
                        },
                    });
                }
            }
        }

        return Array.from(buckets.entries())
            .sort(([a], [b]) => a - b)
            .map(([_, bucket]) => {
                const row: ChartRow = {
                    timestamp: bucket.timestamp,
                    timestampMs: new Date(bucket.timestamp).getTime(),
                    time: formatAxisTime(bucket.timestamp, chart.timeRange),
                };

                for (const variable of chart.variables) {
                    const values = bucket.values[variable.key];

                    row[variable.key] =
                        values && values.length > 0
                            ? average(values)
                            : null;
                }

                return row;
            });
    }, [chart.variables, chart.timeRange, chart.interval]);

    const displayData = useMemo(
        () => downsampleRows(data, maxRowsForRange(chart.timeRange)),
        [data, chart.timeRange],
    );

    const stats = useMemo(() => {
        if (!primaryVariable) {
            return {
                current: null,
                average: null,
                max: null,
                min: null,
                change: null,
                count: 0,
            };
        }

        const values = primaryVariable.data
            .map((point) => point.value)
            .filter(
                (value): value is number =>
                    typeof value === "number" &&
                    Number.isFinite(value),
            );

        if (values.length === 0) {
            return {
                current: null,
                average: null,
                max: null,
                min: null,
                change: null,
                count: 0,
            };
        }

        const current = values[values.length - 1];
        const first = values[0];

        return {
            current,
            average: values.reduce((sum, value) => sum + value, 0) / values.length,
            max: Math.max(...values),
            min: Math.min(...values),
            change: current - first,
            count: values.length,
        };
    }, [primaryVariable]);

    const yDomain: [number | "auto", number | "auto"] = zeroBaseline
        ? [0, "auto"]
        : ["auto", "auto"];

    const allowedIntervalOptions = useMemo(() => {
        if (chart.mode === "bar") {
            return INTERVAL_OPTIONS.filter((option) =>
                ["5m", "15m", "1h"].includes(option.value),
            );
        }

        return INTERVAL_OPTIONS;
    }, [chart.mode]);

    return (
        <section
            className={
                detached
                    ? isDark
                        ? `${RADIUS} flex h-full min-h-0 flex-col overflow-hidden border-0 bg-[#0F1726] text-slate-100`
                        : `${RADIUS} flex h-full min-h-0 flex-col overflow-hidden border-0 bg-white text-slate-950`
                    : isDark
                        ? `${RADIUS} flex h-full min-h-0 flex-col overflow-hidden border border-[#223049] bg-[#0F1726] text-slate-100 shadow-[0_18px_50px_rgba(0,0,0,0.24)]`
                        : `${RADIUS} flex h-full min-h-0 flex-col overflow-hidden border border-slate-200 bg-white text-slate-950 shadow-[0_14px_34px_rgba(15,23,42,0.08)]`
            }
        >
            <header
                onPointerDown={onHeaderPointerDown}
                className="flex shrink-0 items-start justify-between gap-3 px-3 py-3 sm:px-4"
            >
                <div className="flex min-w-0 flex-1 items-start gap-3">
                    {dragHandle && <div className="mt-1 shrink-0">{dragHandle}</div>}

                    {(chart.title || chart.subtitle) && (
                        <div className="min-w-0 flex-1">
                            {chart.title ? (
                                <div className="flex min-w-0 items-center gap-2">
                                    <h2 className="truncate text-[19px] font-black tracking-[-0.035em]">
                                        {chart.title}
                                    </h2>

                                    <span
                                        className={
                                            chart.status === "online"
                                                ? "h-2 w-2 rounded-full bg-[#4FD1C5]"
                                                : "h-2 w-2 rounded-full bg-slate-500"
                                        }
                                    />
                                </div>
                            ) : null}

                            {chart.subtitle ? (
                                <p className="mt-1 truncate text-xs text-[#8290A6]">
                                    {chart.subtitle}
                                </p>
                            ) : null}
                        </div>
                    )}
                </div>

                <div className="flex shrink-0 items-center gap-1.5">
                    {onSave && (
                        <button
                            type="button"
                            onClick={onSave}
                            title="Guardar gráfico"
                            className={windowButtonClass(isDark)}
                        >
                            <Save className="h-4 w-4" />
                        </button>
                    )}

                    {onExport && (
                        <button
                            type="button"
                            onClick={onExport}
                            title="Exportar gráfico"
                            className={windowButtonClass(isDark)}
                        >
                            <Download className="h-4 w-4" />
                        </button>
                    )}

                    {onDetach && onAttach && (
                        <button
                            type="button"
                            onClick={detached ? onAttach : onDetach}
                            title={detached ? "Repor janela" : "Destacar janela"}
                            className={windowButtonClass(isDark)}
                        >
                            <Maximize2 className="h-4 w-4" />
                        </button>
                    )}
                </div>
            </header>

            <main className="flex min-h-0 flex-1 flex-col px-3 pb-3 sm:px-4 sm:pb-4">
                <section
                    className={
                        isDark
                            ? `${RADIUS} flex min-h-0 flex-1 flex-col bg-[#09111F] p-2 sm:p-3`
                            : `${RADIUS} flex min-h-0 flex-1 flex-col bg-slate-50 p-2 sm:p-3`
                    }
                >
                    <div className="mb-2 flex shrink-0 items-center justify-between gap-2">
                        <div className="relative">
                            <button
                                type="button"
                                onClick={() => setRangeMenuOpen((value) => !value)}
                                className={buttonClass(isDark)}
                            >
                                Período: {formatRangeLabel(chart.timeRange)}
                                <ChevronDown className="ml-1.5 inline h-3 w-3" />
                            </button>

                            {rangeMenuOpen && (
                                <DropdownPanel
                                    isDark={isDark}
                                    className="left-0 top-9 grid w-36 grid-cols-2"
                                >
                                    {RANGE_OPTIONS.map((range) => (
                                        <button
                                            key={range.value}
                                            type="button"
                                            onClick={() => {
                                                onTimeRangeChange(range.value);
                                                setRangeMenuOpen(false);
                                            }}
                                            className={
                                                chart.timeRange === range.value
                                                    ? activeButtonClass(isDark)
                                                    : buttonClass(isDark)
                                            }
                                        >
                                            {range.label}
                                        </button>
                                    ))}
                                </DropdownPanel>
                            )}
                        </div>

                        <div className="ml-auto flex shrink-0 items-center gap-1.5">
                            <div className="relative">
                                <button
                                    type="button"
                                    onClick={() => setIntervalMenuOpen((value) => !value)}
                                    className={buttonClass(isDark)}
                                >
                                    Intervalo: {formatIntervalLabel(chart.interval)}
                                    <ChevronDown className="ml-1.5 inline h-3 w-3" />
                                </button>

                                {intervalMenuOpen && (
                                    <DropdownPanel
                                        isDark={isDark}
                                        className="right-0 top-9 grid w-32 grid-cols-1"
                                    >
                                        {allowedIntervalOptions.map((interval) => (
                                            <button
                                                key={interval.value}
                                                type="button"
                                                onClick={() => {
                                                    onIntervalChange(interval.value);
                                                    setIntervalMenuOpen(false);
                                                }}
                                                className={
                                                    chart.interval === interval.value
                                                        ? activeButtonClass(isDark)
                                                        : buttonClass(isDark)
                                                }
                                            >
                                                {interval.label}
                                            </button>
                                        ))}
                                    </DropdownPanel>
                                )}
                            </div>

                            <div className="relative">
                                <button
                                    type="button"
                                    onClick={() => setModeMenuOpen((value) => !value)}
                                    className={buttonClass(isDark)}
                                >
                                    Tipo: {formatModeLabel(chart.mode)}
                                    <ChevronDown className="ml-1.5 inline h-3 w-3" />
                                </button>

                                {modeMenuOpen && (
                                    <DropdownPanel
                                        isDark={isDark}
                                        className="right-0 top-9 grid w-32 grid-cols-1"
                                    >
                                        {(["line", "area", "bar"] as WorkspaceChartMode[]).map(
                                            (mode) => (
                                                <button
                                                    key={mode}
                                                    type="button"
                                                    onClick={() => {
                                                        onModeChange(mode);
                                                        setModeMenuOpen(false);
                                                    }}
                                                    className={
                                                        chart.mode === mode
                                                            ? activeButtonClass(isDark)
                                                            : buttonClass(isDark)
                                                    }
                                                >
                                                    {formatModeLabel(mode)}
                                                </button>
                                            ),
                                        )}
                                    </DropdownPanel>
                                )}
                            </div>

                            <button
                                type="button"
                                onClick={() => setShowIndicators((value) => !value)}
                                className={
                                    showIndicators
                                        ? activeButtonClass(isDark)
                                        : buttonClass(isDark)
                                }
                            >
                                <Activity className="mr-1.5 inline h-3.5 w-3.5" />
                                Indicadores
                            </button>

                            <div className="relative">
                                <button
                                    type="button"
                                    onClick={() => setVariableMenuOpen((value) => !value)}
                                    className={iconButtonClass(isDark)}
                                    title="Configurar variáveis"
                                >
                                    <Settings2 className="h-3.5 w-3.5" />
                                </button>

                                {variableMenuOpen && (
                                    <DropdownPanel
                                        isDark={isDark}
                                        className="right-0 top-9 w-72"
                                    >
                                        <p className="mb-2 px-2 text-[10px] font-bold uppercase tracking-[0.16em] text-[#7F8CA3]">
                                            Variáveis registadas
                                        </p>

                                        <div className="max-h-[260px] overflow-y-auto pr-1">
                                            {chart.variables.map((variable) => (
                                                <button
                                                    key={variable.key}
                                                    type="button"
                                                    onClick={() =>
                                                        onVariableToggle(variable.key)
                                                    }
                                                    className={
                                                        isDark
                                                            ? `${RADIUS} flex w-full items-center justify-between px-2 py-2 text-xs font-semibold text-slate-300 hover:bg-white/[0.05]`
                                                            : `${RADIUS} flex w-full items-center justify-between px-2 py-2 text-xs font-semibold text-slate-700 hover:bg-slate-100`
                                                    }
                                                >
                                                    <span className="flex min-w-0 items-center gap-2">
                                                        <span
                                                            className="h-2.5 w-2.5 shrink-0 rounded-full"
                                                            style={{
                                                                backgroundColor:
                                                                    variable.color,
                                                            }}
                                                        />
                                                        <span className="truncate">
                                                            {variable.label}
                                                        </span>
                                                    </span>

                                                    <span
                                                        className={
                                                            variable.visible
                                                                ? "text-[#4FD1C5]"
                                                                : "text-slate-600"
                                                        }
                                                    >
                                                        {variable.visible ? "ON" : "OFF"}
                                                    </span>
                                                </button>
                                            ))}
                                        </div>
                                    </DropdownPanel>
                                )}
                            </div>

                            <button
                                type="button"
                                onClick={() => setZeroBaseline((value) => !value)}
                                className={iconButtonClass(isDark, zeroBaseline)}
                                title="Fixar base em zero"
                            >
                                <SlidersHorizontal className="h-3.5 w-3.5" />
                            </button>
                        </div>
                    </div>

                    <div className="mb-2 flex shrink-0 items-center justify-between gap-3 overflow-x-auto pb-1">
                        <div className="flex shrink-0 items-center gap-4 text-[11px]">
                            {visibleVariables.map((variable) => (
                                <span
                                    key={variable.key}
                                    className={
                                        isDark
                                            ? "font-semibold text-slate-300"
                                            : "font-semibold text-slate-700"
                                    }
                                >
                                    <span
                                        className="mr-2 inline-block h-2 w-2 rounded-full"
                                        style={{ backgroundColor: variable.color }}
                                    />
                                    {variable.label}
                                    {variable.unit && ` (${displayUnit(variable.unit)})`}
                                </span>
                            ))}
                        </div>

                        {primaryVariable && showIndicators && (
                            <div className="ml-auto flex shrink-0 items-center gap-4 text-[11px] text-[#8290A6]">
                                <span>
                                    Média:{" "}
                                    <b>{formatValue(stats.average, displayUnit(primaryVariable.unit))}</b>
                                </span>
                                <span>
                                    Máx:{" "}
                                    <b>{formatValue(stats.max, displayUnit(primaryVariable.unit))}</b>
                                </span>
                                <span>
                                    Mín:{" "}
                                    <b>{formatValue(stats.min, displayUnit(primaryVariable.unit))}</b>
                                </span>
                            </div>
                        )}
                    </div>

                    <div className="relative min-h-[80px] flex-1">
                        {visibleVariables.length === 0 && !shouldShowLoading ? (
                            <EmptyChartMessage message="Escolha pelo menos uma variável." />
                        ) : data.length === 0 && !shouldShowLoading ? (
                            <EmptyChartMessage message="Sem dados históricos para o período selecionado." />
                        ) : data.length > 0 ? (
                            <ResponsiveContainer width="100%" height="100%">
                                {chart.mode === "bar" ? (
                                    <BarChart data={displayData} barCategoryGap="25%" barGap={4}>
                                        <ChartScaffold
                                            isDark={isDark}
                                            yDomain={yDomain}
                                            yAxes={yAxes}
                                            chartTimeRange={chart.timeRange}
                                        />
                                        {visibleVariables.map((variable) => (
                                            <Bar
                                                key={variable.key}
                                                name={variable.label}
                                                unit={displayUnit(variable.unit)}
                                                dataKey={variable.key}
                                                yAxisId={getYAxisId(variable, yAxes)}
                                                fill={variable.color}
                                                radius={[3, 3, 0, 0]}
                                                opacity={0.78}
                                                isAnimationActive={false}
                                                maxBarSize={42}
                                            />
                                        ))}
                                    </BarChart>
                                ) : chart.mode === "area" ? (
                                    <AreaChart data={displayData}>
                                        <ChartScaffold
                                            isDark={isDark}
                                            yDomain={yDomain}
                                            yAxes={yAxes}
                                            chartTimeRange={chart.timeRange}
                                        />
                                        {renderReferenceLines(
                                            visibleVariables,
                                            showIndicators,
                                            stats.average,
                                        )}
                                        {visibleVariables.map((variable) => (
                                            <Area
                                                key={variable.key}
                                                name={variable.label}
                                                unit={displayUnit(variable.unit)}
                                                type="monotone"
                                                dataKey={variable.key}
                                                yAxisId={getYAxisId(variable, yAxes)}
                                                stroke={variable.color}
                                                fill={variable.color}
                                                fillOpacity={0.08}
                                                strokeWidth={2}
                                                dot={false}
                                                activeDot={{ r: 4 }}
                                                isAnimationActive={false}
                                                connectNulls={false}
                                            />
                                        ))}
                                    </AreaChart>
                                ) : (
                                    <LineChart data={displayData}>
                                        <ChartScaffold
                                            isDark={isDark}
                                            yDomain={yDomain}
                                            yAxes={yAxes}
                                            chartTimeRange={chart.timeRange}
                                        />
                                        {renderReferenceLines(
                                            visibleVariables,
                                            showIndicators,
                                            stats.average,
                                        )}
                                        {visibleVariables.map((variable) => (
                                            <Line
                                                key={variable.key}
                                                name={variable.label}
                                                unit={displayUnit(variable.unit)}
                                                type="monotone"
                                                dataKey={variable.key}
                                                yAxisId={getYAxisId(variable, yAxes)}
                                                stroke={variable.color}
                                                strokeWidth={2}
                                                dot={false}
                                                activeDot={{ r: 4 }}
                                                isAnimationActive={false}
                                                connectNulls={false}
                                            />
                                        ))}
                                    </LineChart>
                                )}
                            </ResponsiveContainer>
                        ) : null}

                        {shouldShowLoading && (
                            <div className="absolute inset-0 z-20 flex items-center justify-center rounded-[8px] bg-[#020817]/60 backdrop-blur-sm">
                                <div className="flex items-center gap-3 rounded-[8px] border border-white/10 bg-black/20 px-4 py-3 text-sm font-bold text-white shadow-2xl">
                                    <Loader2 className="h-5 w-5 animate-spin" />
                                    A carregar histórico...
                                </div>
                            </div>
                        )}
                    </div>

                    {showIndicators && primaryVariable && (
                        <div className="mt-2 shrink-0 overflow-x-auto border-t border-white/[0.06] pt-2">
                            <div className="flex min-w-max items-center gap-5 text-xs">
                                <InlineMetric
                                    label="Atual"
                                    value={formatValue(
                                        stats.current,
                                        primaryVariable.unit,
                                    )}
                                    isDark={isDark}
                                />
                                <InlineMetric
                                    label="Variação"
                                    value={formatSignedValue(
                                        stats.change,
                                        primaryVariable.unit,
                                    )}
                                    isDark={isDark}
                                />
                                <InlineMetric
                                    label="Máx"
                                    value={formatValue(stats.max, primaryVariable.unit)}
                                    isDark={isDark}
                                />
                                <InlineMetric
                                    label="Mín"
                                    value={formatValue(stats.min, primaryVariable.unit)}
                                    isDark={isDark}
                                />
                                <InlineMetric
                                    label="Pontos"
                                    value={String(stats.count)}
                                    isDark={isDark}
                                />
                            </div>
                        </div>
                    )}
                </section>
            </main>
        </section>
    );
}

function ChartScaffold({
    isDark,
    yDomain,
    yAxes,
    chartTimeRange
}: {
    isDark: boolean;
    yDomain: [number | "auto", number | "auto"];
    yAxes: YAxisConfig[];
    chartTimeRange: WorkspaceChartTimeRange;
}) {
    return (
        <>
            <CartesianGrid
                stroke={isDark ? "rgba(148,163,184,0.075)" : "#e2e8f0"}
                strokeDasharray="4 7"
                vertical={false}
            />

            <XAxis
                dataKey="timestampMs"
                type="number"
                scale="time"
                domain={["dataMin", "dataMax"]}
                padding={{ left: 24, right: 24 }}
                tick={{ fill: "#64748b", fontSize: 10 }}
                tickLine={false}
                axisLine={{
                    stroke: isDark ? "rgba(148,163,184,0.12)" : "#cbd5e1",
                }}
                minTickGap={34}
                tickFormatter={(value) =>
                    formatAxisTime(new Date(Number(value)).toISOString(), chartTimeRange)
                }
            />
            {yAxes.map((axis) => (
                <YAxis
                    key={axis.id}
                    yAxisId={axis.id}
                    orientation={axis.orientation}
                    domain={yDomain}
                    tick={{ fill: axis.color, fontSize: 10 }}
                    tickLine={false}
                    axisLine={{
                        stroke: isDark ? "rgba(148,163,184,0.18)" : "#cbd5e1",
                    }}
                    width={52}
                    label={
                        axis.unit
                            ? {
                                value: axis.unit,
                                angle: axis.orientation === "left" ? -90 : 90,
                                position:
                                    axis.orientation === "left"
                                        ? "insideLeft"
                                        : "insideRight",
                                fill: axis.color,
                                fontSize: 10,
                            }
                            : undefined
                    }
                />
            ))}

            <Tooltip
                cursor={{
                    fill: "rgba(255,255,255,0.04)",
                    stroke: "rgba(79,209,197,0.12)",
                    strokeWidth: 1,
                }}
                labelFormatter={(_, payload) => {
                    const timestamp = payload?.[0]?.payload?.timestamp;
                    return timestamp ? formatTooltipDate(timestamp) : "";
                }}
                contentStyle={{
                    background: isDark ? "#111827" : "#ffffff",
                    border: isDark
                        ? "1px solid rgba(255,255,255,0.10)"
                        : "1px solid #e2e8f0",
                    borderRadius: 8,
                    color: isDark ? "#e2e8f0" : "#0f172a",
                    boxShadow: "0 16px 34px rgba(0,0,0,0.24)",
                }}
            />
        </>
    );
}

function DropdownPanel({
    isDark,
    className,
    children,
}: {
    isDark: boolean;
    className: string;
    children: React.ReactNode;
}) {
    return (
        <div
            className={
                isDark
                    ? `absolute z-50 gap-1 ${RADIUS} border border-[#263247] bg-[#111827] p-2 shadow-2xl ${className}`
                    : `absolute z-50 gap-1 ${RADIUS} border border-slate-200 bg-white p-2 shadow-xl ${className}`
            }
        >
            {children}
        </div>
    );
}

function EmptyChartMessage({ message }: { message: string }) {
    return (
        <div className="flex h-full items-center justify-center text-center text-sm font-semibold text-[#7F8CA3]">
            {message}
        </div>
    );
}

function renderReferenceLines(
    visibleVariables: WorkspaceChartVariable[],
    showIndicators: boolean,
    average: number | null,
) {
    return (
        <>
            {showIndicators && average !== null && (
                <ReferenceLine
                    y={average}
                    stroke="#94a3b8"
                    strokeDasharray="4 5"
                    strokeOpacity={0.28}
                />
            )}

            {visibleVariables.map((variable) =>
                variable.limit !== undefined ? (
                    <ReferenceLine
                        key={`${variable.key}-limit`}
                        y={variable.limit}
                        stroke="#ef4444"
                        strokeDasharray="6 6"
                        strokeOpacity={0.55}
                    />
                ) : null,
            )}
        </>
    );
}

function InlineMetric({
    label,
    value,
    isDark,
}: {
    label: string;
    value: string;
    isDark: boolean;
}) {
    return (
        <span className="text-[#8290A6]">
            {label}:{" "}
            <b className={isDark ? "font-black text-slate-100" : "font-black text-slate-950"}>
                {value}
            </b>
        </span>
    );
}

function buttonClass(isDark: boolean) {
    return isDark
        ? `${RADIUS} h-8 shrink-0 whitespace-nowrap border border-[#24334D] bg-white/[0.025] px-3 text-[11px] font-semibold text-slate-300 transition hover:bg-white/[0.06] hover:text-slate-100`
        : `${RADIUS} h-8 shrink-0 whitespace-nowrap border border-slate-200 bg-white px-3 text-[11px] font-semibold text-slate-600 transition hover:bg-slate-100 hover:text-slate-950`;
}

function activeButtonClass(isDark: boolean) {
    return isDark
        ? `${RADIUS} h-8 shrink-0 whitespace-nowrap border border-[#4FD1C5] bg-[#4FD1C5] px-3 text-[11px] font-black text-[#07101B]`
        : `${RADIUS} h-8 shrink-0 whitespace-nowrap border border-[#0F766E] bg-[#0F766E] px-3 text-[11px] font-black text-white`;
}

function iconButtonClass(isDark: boolean, active = false) {
    if (active) {
        return isDark
            ? `${RADIUS} flex h-8 w-8 shrink-0 items-center justify-center border border-[#4FD1C5] bg-[#4FD1C5] text-[#07101B]`
            : `${RADIUS} flex h-8 w-8 shrink-0 items-center justify-center border border-[#0F766E] bg-[#0F766E] text-white`;
    }

    return isDark
        ? `${RADIUS} flex h-8 w-8 shrink-0 items-center justify-center border border-[#24334D] bg-white/[0.025] text-slate-400 transition hover:bg-white/[0.06] hover:text-slate-100`
        : `${RADIUS} flex h-8 w-8 shrink-0 items-center justify-center border border-slate-200 bg-white text-slate-500 transition hover:bg-slate-100 hover:text-slate-950`;
}

function windowButtonClass(isDark: boolean) {
    return isDark
        ? `${RADIUS} p-2 text-slate-500 transition hover:bg-white/5 hover:text-white`
        : `${RADIUS} p-2 text-slate-400 transition hover:bg-slate-100 hover:text-slate-900`;
}

function formatValue(value: number | null, unit?: string) {
    if (value === null || Number.isNaN(value)) return "--";

    const normalizedUnit = displayUnit(unit);

    return `${value.toFixed(1)}${normalizedUnit ? ` ${normalizedUnit}` : ""}`;
}

function formatSignedValue(value: number | null, unit?: string) {
    if (value === null || Number.isNaN(value)) return "--";

    const prefix = value >= 0 ? "+" : "";
    const normalizedUnit = displayUnit(unit);

    return `${prefix}${value.toFixed(1)}${normalizedUnit ? ` ${normalizedUnit}` : ""}`;
}
function formatRangeLabel(range: WorkspaceChartTimeRange) {
    return range.toUpperCase();
}

function formatIntervalLabel(interval: WorkspaceChartInterval) {
    return interval;
}

function formatModeLabel(mode: WorkspaceChartMode) {
    if (mode === "line") return "Linha";
    if (mode === "area") return "Área";
    return "Barras";
}

function formatAxisTime(timestamp: string, range: WorkspaceChartTimeRange) {
    const date = new Date(timestamp);

    if (range === "7d") {
        return date.toLocaleString("pt-PT", {
            day: "2-digit",
            month: "2-digit",
            hour: "2-digit",
        });
    }

    if (range === "30d") {
        return date.toLocaleDateString("pt-PT", {
            day: "2-digit",
            month: "2-digit",
        });
    }

    return date.toLocaleTimeString("pt-PT", {
        hour: "2-digit",
        minute: "2-digit",
    });
}
function formatTooltipDate(timestamp: string) {
    return new Date(timestamp).toLocaleString("pt-PT", {
        day: "2-digit",
        month: "2-digit",
        year: "numeric",
        hour: "2-digit",
        minute: "2-digit",
    });
}

function rangeToMs(range: WorkspaceChartTimeRange) {
    switch (range) {
        case "15m":
            return 15 * 60 * 1000;
        case "1h":
            return 60 * 60 * 1000;
        case "6h":
            return 6 * 60 * 60 * 1000;
        case "24h":
            return 24 * 60 * 60 * 1000;
        case "7d":
            return 7 * 24 * 60 * 60 * 1000;
        case "30d":
            return 30 * 24 * 60 * 60 * 1000;
    }
}

function intervalToMs(interval: WorkspaceChartInterval) {
    switch (interval) {
        case "1m":
            return 60 * 1000;
        case "5m":
            return 5 * 60 * 1000;
        case "15m":
            return 15 * 60 * 1000;
        case "1h":
            return 60 * 60 * 1000;
    }
}

function average(values: number[]) {
    return values.reduce((sum, value) => sum + value, 0) / values.length;
}

function buildYAxisConfigs(
    variables: WorkspaceChartVariable[],
): YAxisConfig[] {
    const uniqueUnits = Array.from(
        new Set(
            variables.map((variable) => normalizeUnit(variable.unit)),
        ),
    );

    const limitedUnits = uniqueUnits.slice(0, 2);

    if (limitedUnits.length === 0) {
        return [
            {
                id: "axis-default",
                unit: "",
                orientation: "left",
                color: "#64748b",
            },
        ];
    }

    return limitedUnits.map((unit, index) => {
        const variable = variables.find(
            (item) => normalizeUnit(item.unit) === unit,
        );

        return {
            id: axisIdForUnit(unit),
            unit,
            orientation: index === 0 ? "left" : "right",
            color: variable?.color ?? "#64748b",
        };
    });
}

function getYAxisId(
    variable: WorkspaceChartVariable,
    axes: YAxisConfig[],
): string {
    const unit = normalizeUnit(variable.unit);

    return (
        axes.find((axis) => axis.unit === unit)?.id ??
        axes[0]?.id ??
        "axis-default"
    );
}

function axisIdForUnit(unit: string): string {
    return `axis-${unit || "default"}`;
}

function normalizeUnit(unit?: string): string {
    return displayUnit(unit);
}

function maxRowsForRange(range: WorkspaceChartTimeRange) {
    if (range === "15m") return 900;
    if (range === "1h") return 900;
    if (range === "6h") return 1200;
    if (range === "24h") return 1600;
    if (range === "7d") return 2500;
    return 3000;
}

function downsampleRows(rows: ChartRow[], maxRows: number) {
    if (rows.length <= maxRows) return rows;

    const step = Math.ceil(rows.length / maxRows);

    return rows.filter((_, index) => index % step === 0);
}

export default WorkspaceChart;