import { Fragment, memo, useState, useRef, useMemo } from "react";
import {
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
  Area,
  Bar,
  ComposedChart,
  ReferenceArea,
  ReferenceLine,
  Line,
  LabelList,
} from "recharts";
import type { GraphDataset } from "../../types/medical";
import { format, parseISO } from "date-fns";
import { X, GripVertical, Split, Merge, Settings, Download, ArrowUp, ArrowDown } from "lucide-react";
import { useDroppable } from "@dnd-kit/core";
import type { DraggableAttributes } from "@dnd-kit/core";
import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities";
import { cn, formatDateRange } from "../../utils/helpers";
import * as htmlToImage from 'html-to-image';
import {
  MedicationShape,
  createChartTooltip,
  createLineEndLabel,
  createOutOfRangeIndicatorDot,
  createPointRenderer,
  getLastNonNullIndex,
} from "./graphChartRenderers.tsx";

interface ChartComponentProps {
  id: string;
  datasets: GraphDataset[];
  onRemove?: () => void;
  onMoveUp?: () => void;
  onMoveDown?: () => void;
  onSplit?: () => void;
  onSplitDataset?: (datasetId: string) => void;
  normalizeByReference?: boolean;
  onNormalizeByReferenceChange?: (enabled: boolean) => void;
  onDatasetColorChange?: (datasetId: string, color: string) => void;
  onDatasetStyleChange?: (
    datasetId: string,
    styleUpdate: Partial<Pick<GraphDataset, "lineStyle" | "pointStyle">>
  ) => void;
  isDragging?: boolean;
  dragAttributes?: DraggableAttributes;
  dragListeners?: SyntheticListenerMap;
}

interface ChartCanvasProps {
  id: string;
  datasets: GraphDataset[];
  mergedData: any[];
  xAxisDomain: [number, number];
  normalizeByReference: boolean;
  seriesAnimationDuration: number;
}

const ChartCanvas = memo(function ChartCanvas({
  id,
  datasets,
  mergedData,
  xAxisDomain,
  normalizeByReference,
  seriesAnimationDuration,
}: ChartCanvasProps) {
  const standardDatasets = datasets.filter((d) => d.type !== "medication");
  const medicationDatasets = datasets.filter((d) => d.type === "medication");

  const uniqueUnits = Array.from(new Set(standardDatasets.map((d) => d.unit)));
  const getAxisId = (unit: string) => `axis-${unit}`;
  const normalizedStandardDatasets = standardDatasets.filter(
    (dataset) => dataset.refMin !== undefined && dataset.refMax !== undefined
  );
  const hasNormalizedAxis = normalizeByReference && normalizedStandardDatasets.length > 0;
  const normalizedAxisId = "axis-normalized";

  const getDatasetAxisId = (dataset: GraphDataset): string => {
    if (
      normalizeByReference &&
      dataset.type !== "medication" &&
      dataset.refMin !== undefined &&
      dataset.refMax !== undefined
    ) {
      return normalizedAxisId;
    }

    return getAxisId(dataset.unit);
  };

  const formatNormalizedTick = (value: number): string => {
    const rounded = Math.round((value + Number.EPSILON) * 1000) / 1000;
    return rounded.toFixed(3);
  };
  const renderTooltip = createChartTooltip(datasets, normalizeByReference);
  const renderDot = createPointRenderer;
  const renderOutOfRangeIndicatorDot = createOutOfRangeIndicatorDot;
  const renderLineEndLabel = createLineEndLabel;

  return (
    <ResponsiveContainer width="100%" height="100%">
      <ComposedChart data={mergedData} margin={{ top: 40, right: 20, left: 20, bottom: 0 }}>
        <defs>
          {datasets.map((ds) => (
            <linearGradient key={ds.instanceId ?? ds.id} id={`color-${id}-${ds.instanceId ?? ds.id}`} x1="0" y1="0" x2="0" y2="1">
              <stop offset="5%" stopColor={ds.color} stopOpacity={0.2} />
              <stop offset="95%" stopColor={ds.color} stopOpacity={0} />
            </linearGradient>
          ))}
        </defs>
        <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#f1f5f9" />

        <XAxis
          dataKey="dateObj"
          type="number"
          domain={xAxisDomain}
          tick={{ fontSize: 11, fill: '#94a3b8' }}
          tickFormatter={(val) => format(new Date(val), "d MMM")}
          axisLine={false}
          tickLine={false}
          dy={10}
          minTickGap={30}
        />

        {hasNormalizedAxis && (
          <YAxis
            key={normalizedAxisId}
            yAxisId={normalizedAxisId}
            orientation="left"
            tick={{ fontSize: 11, fill: '#94a3b8' }}
            tickFormatter={(value) => formatNormalizedTick(Number(value))}
            axisLine={false}
            tickLine={false}
            dx={-5}
            domain={[-1, 1]}
            label={{
              value: "normalized",
              angle: -90,
              position: 'insideLeft',
              style: { fill: '#cbd5e1', fontSize: 10, textAnchor: 'middle' }
            }}
          />
        )}

        {uniqueUnits.map((unit, index) => {
          const isLeft = index === 0;
          const unitDatasets = standardDatasets.filter(d => d.unit === unit);
          const allHaveReferences = unitDatasets.every(d => d.refMin !== undefined && d.refMax !== undefined);
          const shouldNormalize = normalizeByReference && allHaveReferences;

          if (shouldNormalize) return null;

          return (
            <YAxis
              key={unit}
              yAxisId={getAxisId(unit || '')}
              orientation={isLeft ? "left" : "right"}
              tick={{ fontSize: 11, fill: isLeft ? '#94a3b8' : '#cbd5e1' }}
              tickFormatter={shouldNormalize ? (value) => formatNormalizedTick(Number(value)) : undefined}
              axisLine={false}
              tickLine={false}
              dx={isLeft ? -5 : 5}
              domain={shouldNormalize ? [-1, 1] : ["auto", "auto"]}
              label={{
                value: shouldNormalize ? `${unit} (normalized)` : unit,
                angle: -90,
                position: isLeft ? 'insideLeft' : 'insideRight',
                style: { fill: '#cbd5e1', fontSize: 10, textAnchor: 'middle' }
              }}
            />
          )
        })}

        {hasNormalizedAxis && (
          <Fragment key="normalized-reference-lines">
            <ReferenceLine
              yAxisId={normalizedAxisId}
              y={0}
              stroke="#cbd5e1"
              strokeOpacity={0.5}
              strokeDasharray="2 4"
              strokeWidth={1}
              ifOverflow="extendDomain"
            />
            <ReferenceLine
              yAxisId={normalizedAxisId}
              y={-1}
              stroke="#94a3b8"
              strokeDasharray="5 4"
              strokeWidth={1.5}
              ifOverflow="extendDomain"
              label={{ value: "MIN", position: "insideBottomRight", fill: "#64748b", fontSize: 10, fontWeight: 700 }}
            />
            <ReferenceLine
              yAxisId={normalizedAxisId}
              y={1}
              stroke="#94a3b8"
              strokeDasharray="5 4"
              strokeWidth={1.5}
              ifOverflow="extendDomain"
              label={{ value: "MAX", position: "insideTopRight", fill: "#64748b", fontSize: 10, fontWeight: 700 }}
            />
          </Fragment>
        )}

        {standardDatasets.length === 0 && (
          <YAxis hide yAxisId={0} domain={[0, 1]} />
        )}

        <Tooltip
          cursor={{ stroke: '#cbd5e1', strokeDasharray: '4 4' }}
          content={renderTooltip}
        />

        {standardDatasets.length === 0 && medicationDatasets.length > 0 && (
          <Line
            yAxisId={0}
            type="linear"
            dataKey="_dummy"
            stroke="transparent"
            dot={false}
            strokeWidth={0}
            isAnimationActive={false}
          />
        )}

        {medicationDatasets.map((ds) => {
          if (ds.data.length === 0) return null;
          const sorted = [...ds.data].sort((a, b) => a.date.localeCompare(b.date));
          const start = parseISO(sorted[0].date).getTime();
          const end = parseISO(sorted[sorted.length - 1].date).getTime();
          const yAxisId = hasNormalizedAxis ? normalizedAxisId : uniqueUnits.length > 0 ? getAxisId(uniqueUnits[0] || '') : 0;

          return (
            <ReferenceArea
              key={ds.instanceId ?? ds.id}
              x1={start}
              x2={end}
              y1={0}
              y2={1}
              ifOverflow="visible"
              yAxisId={yAxisId}
              shape={(props) => <MedicationShape {...props} fill={ds.color} name={ds.name} />}
            />
          )
        })}

        {standardDatasets.map((ds) => {
          const axisId = getDatasetAxisId(ds);
          if (ds.type === 'medication') {
            return (
              <Bar
                key={ds.instanceId ?? ds.id}
                yAxisId={axisId}
                dataKey={ds.id}
                fill={ds.color}
                radius={4}
                barSize={20}
                animationDuration={seriesAnimationDuration}
                animationBegin={0}
                name={ds.name}
              />
            );
          }

          return (
            <Fragment key={ds.instanceId ?? ds.id}>
              <Line
                yAxisId={axisId}
                type="linear"
                dataKey={`${ds.id}__refMin`}
                stroke={ds.color}
                strokeOpacity={0.55}
                strokeDasharray="5 4"
                strokeWidth={1.5}
                dot={false}
                activeDot={false}
                connectNulls
                isAnimationActive={false}
                name={`${ds.name} min`}
                hide={normalizeByReference}
              >
                <LabelList content={renderLineEndLabel("MIN", ds.color, 10, getLastNonNullIndex(mergedData, `${ds.id}__refMin`))} />
              </Line>
              <Line
                yAxisId={axisId}
                type="linear"
                dataKey={`${ds.id}__refMax`}
                stroke={ds.color}
                strokeOpacity={0.55}
                strokeDasharray="5 4"
                strokeWidth={1.5}
                dot={false}
                activeDot={false}
                connectNulls
                isAnimationActive={false}
                name={`${ds.name} max`}
                hide={normalizeByReference}
              >
                <LabelList content={renderLineEndLabel("MAX", ds.color, -6, getLastNonNullIndex(mergedData, `${ds.id}__refMax`))} />
              </Line>
              <Line
                yAxisId={axisId}
                type="linear"
                dataKey={`${ds.id}__outOfRangeIndicator`}
                stroke="transparent"
                strokeWidth={0}
                dot={renderOutOfRangeIndicatorDot}
                activeDot={false}
                connectNulls={false}
                isAnimationActive={false}
                name={`${ds.name} out-of-range indicator`}
              />
              <Area
                yAxisId={axisId}
                type="linear"
                dataKey={ds.id}
                stroke={ds.color}
                strokeDasharray={ds.lineStyle === "dashed" ? "6 4" : undefined}
                strokeWidth={3}
                fillOpacity={1}
                fill={`url(#color-${id}-${ds.instanceId ?? ds.id})`}
                dot={renderDot(ds.pointStyle ?? "circle", ds.color)}
                activeDot={renderDot(ds.pointStyle ?? "circle", ds.color, true)}
                animationDuration={seriesAnimationDuration}
                animationBegin={0}
                connectNulls
                name={ds.name}
              />
            </Fragment>
          );
        })}
      </ComposedChart>
    </ResponsiveContainer>
  );
});

export function ChartComponent({ 
  id, 
  datasets, 
  onRemove, 
  onMoveUp,
  onMoveDown,
  onSplit, 
  onSplitDataset,
  normalizeByReference = false,
  onNormalizeByReferenceChange,
  onDatasetColorChange,
  onDatasetStyleChange,
  isDragging,
  dragAttributes,
  dragListeners
}: ChartComponentProps) {
  const seriesAnimationDuration = 500;
  const [showSettings, setShowSettings] = useState(false);
  const [selectedEditDatasetId, setSelectedEditDatasetId] = useState<string | null>(null);
  const [chartHeight, setChartHeight] = useState<"small" | "medium" | "large">("medium");
  const chartRef = useRef<HTMLDivElement>(null);

  // Define a drop zone for merging
  const { setNodeRef, isOver } = useDroppable({
    id: `merge-${id}`,
    data: { type: 'merge-target', graphId: id }
  });

  // --- Data Preparation (with optional Normalization) ---
  // Normalize a value based on reference range (scales to -1 to 1 range where midpoint is reference center)
  const normalizeValue = (value: number, refMin?: number, refMax?: number): number => {
    if (refMin === undefined || refMax === undefined || refMax <= refMin) return value;
    const range = refMax - refMin;
    const midpoint = (refMin + refMax) / 2;
    // Scale values to -1 to 1 range centered at reference midpoint
    return (value - midpoint) / (range / 2);
  };

  const roundToThreeDecimals = (value: number): number => {
    return Math.round((value + Number.EPSILON) * 1000) / 1000;
  };

  const mergedData = useMemo(() => {
    if (!datasets.length) return [];

    // 1. Collect all unique dates
    const dateSet = new Set<string>();
    datasets.forEach(ds => ds.data.forEach(p => dateSet.add(p.date)));
    const sortedDates = Array.from(dateSet).sort();

    // 2. Create unified objects
    return sortedDates.map(date => {
      const entry: any = { date, dateObj: parseISO(date).getTime() };
      datasets.forEach(ds => {
        const point = ds.data.find(d => d.date === date);
        const rawValue = point ? point.value : null;
        let value = rawValue;
        const pointRefMin = point?.refMin;
        const pointRefMax = point?.refMax;
        let outOfRangeIndicatorValue: number | null = null;
        
        // Apply normalization if enabled and point-level reference range exists
        if (normalizeByReference && value !== null && pointRefMin !== undefined && pointRefMax !== undefined) {
          value = roundToThreeDecimals(normalizeValue(value, pointRefMin, pointRefMax));
        }

        if (
          rawValue !== null &&
          typeof rawValue === "number" &&
          pointRefMin !== undefined &&
          pointRefMax !== undefined
        ) {
          if (rawValue < pointRefMin || rawValue > pointRefMax) {
            // Keep the indicator at the same plotted height as the out-of-range point.
            outOfRangeIndicatorValue = value;
          }
        }
        
        entry[ds.id] = value;
        entry[`${ds.id}__refMin`] = pointRefMin !== undefined
          ? (normalizeByReference && pointRefMax !== undefined ? roundToThreeDecimals(normalizeValue(pointRefMin, pointRefMin, pointRefMax)) : pointRefMin)
          : null;
        entry[`${ds.id}__refMax`] = pointRefMax !== undefined
          ? (normalizeByReference && pointRefMin !== undefined ? roundToThreeDecimals(normalizeValue(pointRefMax, pointRefMin, pointRefMax)) : pointRefMax)
          : null;
        entry[`${ds.id}__outOfRangeIndicator`] = outOfRangeIndicatorValue;
      });
      // Add a dummy value for medication-only charts to help establish scale
      entry['_dummy'] = normalizeByReference ? 0 : 0.5;
      return entry;
    });
  }, [datasets, normalizeByReference]);

  // Calculate X-axis domain for proper time-proportional spacing
  const xAxisDomain = useMemo<[number, number]>(() => {
    if (mergedData.length === 0) return [0, 1];
    const timestamps = mergedData.map(d => d.dateObj);
    const minTime = Math.min(...timestamps);
    const maxTime = Math.max(...timestamps);
    // Add 5% padding on each side for visual spacing
    const range = maxTime - minTime;
    const padding = range * 0.05;
    return [minTime - padding, maxTime + padding];
  }, [mergedData]);

  const standardDatasets = datasets.filter((ds) => ds.type !== "medication");

  // Handle Export
  const handleExport = async () => {
    if (!chartRef.current) return;
    try {
      const exportOptions = {
        backgroundColor: '#ffffff',
        cacheBust: true,
        pixelRatio: 2,
        skipFonts: true,
        filter: (node: HTMLElement) => !node.classList?.contains('export-ignore')
      };

      let dataUrl: string;
      try {
        dataUrl = await htmlToImage.toPng(chartRef.current, exportOptions);
      } catch {
        // Fallback for environments where stylesheet parsing is still attempted.
        dataUrl = await htmlToImage.toPng(chartRef.current, {
          ...exportOptions,
          fontEmbedCSS: '',
        });
      }

      const link = document.createElement('a');
      link.download = `Plot-${datasets.map(d => d.name).join('-')}.png`;
      link.href = dataUrl;
      link.click();
      setShowSettings(false);
      setSelectedEditDatasetId(null);
    } catch (error) {
      console.error("Export failed", error);
    }
  };

  // --- Styles ---
  const heightClass = {
    "small": "h-64",
    "medium": "h-96",
    "large": "h-[500px]"
  }[chartHeight];

  if (!datasets.length) return null;

  const getDatasetKey = (dataset: GraphDataset) => dataset.instanceId ?? dataset.id;

  const editableDatasets = datasets;
  const selectedEditDataset =
    editableDatasets.find((dataset) => getDatasetKey(dataset) === selectedEditDatasetId) ??
    editableDatasets[0];

  return (
    <div
      ref={(node) => {
        setNodeRef(node);
        // @ts-ignore
        chartRef.current = node;
      }}
      className={cn(
        "bg-white rounded-2xl shadow-sm border p-5 flex flex-col transition-all duration-300 relative group",
        heightClass,
        isDragging ? "z-50" : showSettings ? "z-40" : "z-0 hover:z-20",
        isDragging ? "shadow-2xl ring-2 ring-blue-500/20 rotate-1 scale-102 opacity-90 cursor-grabbing" : "hover:shadow-md",
        isOver && !isDragging ? "ring-2 ring-blue-500 ring-offset-2 border-blue-200 bg-blue-50/30 scale-[1.01]" : "border-slate-100"
      )}
    >
      {isOver && !isDragging && (
        <div className="absolute inset-0 flex items-center justify-center bg-white/60 backdrop-blur-[1px] z-20 rounded-2xl border-2 border-dashed border-blue-400 pointer-events-none">
          <div className="flex flex-col items-center text-blue-600 animate-pulse">
            <Merge size={48} />
            <span className="font-bold text-lg">Drop to Compare</span>
          </div>
        </div>
      )}

      <div className="flex justify-between items-start mb-4 relative z-20 gap-3">
        <div className="flex items-start gap-3 min-w-0">
          <div className="flex items-center gap-1">
            <div className="flex flex-col gap-0.5">
              <button
                type="button"
                onClick={onMoveUp}
                className="p-1 text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
                title="Move plot up"
              >
                <ArrowUp size={14} />
              </button>
              <button
                type="button"
                onClick={onMoveDown}
                className="p-1 text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors"
                title="Move plot down"
              >
                <ArrowDown size={14} />
              </button>
            </div>
            <div
              {...dragAttributes}
              {...dragListeners}
              className="cursor-grab active:cursor-grabbing p-2 text-slate-300 hover:text-slate-500 hover:bg-slate-50 rounded-lg transition-colors touch-none"
            >
              <GripVertical size={18} />
            </div>
          </div>

          <div className="min-w-0">
            <div className="flex flex-wrap items-center gap-2">
              {datasets.map((ds) => (
                <div key={getDatasetKey(ds)} className="flex items-center gap-1.5 px-2 py-1 bg-slate-50 rounded-md border border-slate-100">
                  <span className="w-2.5 h-2.5 rounded-full shadow-sm" style={{ backgroundColor: ds.color }} />
                  <span className="text-sm font-semibold text-slate-700 whitespace-nowrap">{ds.name}</span>
                  {ds.type === "medication" && <span className="text-[10px] bg-slate-200 px-1 rounded text-slate-500">MED</span>}
                  {datasets.length > 1 && onSplitDataset && (
                    <button
                      type="button"
                      onClick={() => onSplitDataset(getDatasetKey(ds))}
                      className="ml-1 text-slate-400 hover:text-blue-600 transition-colors"
                      title={`Split ${ds.name} into a new plot`}
                      aria-label={`Split ${ds.name} into a new plot`}
                    >
                      <Split size={12} />
                    </button>
                  )}
                </div>
              ))}
            </div>
            {mergedData.length > 0 && (
              <p className="text-xs text-slate-400 mt-2 pl-1 leading-5">
                {formatDateRange(mergedData[0].date, mergedData[mergedData.length - 1].date)}
              </p>
            )}
          </div>
        </div>

        <div className="flex items-center gap-1 relative">
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation();
              setShowSettings((current) => !current);
            }}
            className={cn(
              "p-2 text-slate-400 hover:text-slate-700 hover:bg-slate-50 rounded-lg transition-colors relative z-30",
              showSettings && "bg-slate-100 text-slate-700"
            )}
          >
            <Settings size={18} />
          </button>

          {datasets.length > 1 && onSplit && (
            <button
              type="button"
              onClick={onSplit}
              className="p-2 text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
              title="Split plots"
            >
              <Split size={18} />
            </button>
          )}

          <button
            type="button"
            onClick={onRemove}
            className="p-2 text-slate-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors"
          >
            <X size={18} />
          </button>

          {showSettings && (
            <>
              <div className="fixed inset-0 z-40" onClick={() => setShowSettings(false)} />
              <div className="export-ignore absolute right-0 top-full mt-2 w-72 bg-white rounded-xl shadow-xl border border-slate-100 p-2 z-50 animate-in fade-in zoom-in-95 duration-200">
                <div className="text-xs font-semibold text-slate-400 px-2 py-1 mb-1">SIZE</div>
                <div className="flex gap-1 mb-3 px-2">
                  {(["small", "medium", "large"] as const).map((size) => (
                    <button
                      key={size}
                      type="button"
                      onClick={() => setChartHeight(size)}
                      className={cn(
                        "flex-1 py-1.5 px-2 rounded-md text-xs border border-slate-200 hover:border-blue-500 transition-colors capitalize",
                        chartHeight === size ? "bg-blue-50 text-blue-600 border-blue-500" : "text-slate-600"
                      )}
                    >
                      {size}
                    </button>
                  ))}
                </div>

                {selectedEditDataset && (onDatasetColorChange || onDatasetStyleChange) && (
                  <>
                    <div className="h-px bg-slate-100 my-1" />
                    <div className="px-2 py-1 mb-1 text-xs font-semibold text-slate-400">PLOT EDITOR</div>
                    <div className="space-y-2 px-2 pb-2">
                      <label className="block text-[11px] text-slate-500">
                        <span className="block mb-1">Parameter</span>
                        <select
                          value={getDatasetKey(selectedEditDataset)}
                          onChange={(e) => setSelectedEditDatasetId(e.target.value)}
                          className="w-full rounded-md border border-slate-200 bg-white px-2 py-1 text-xs text-slate-700"
                        >
                          {editableDatasets.map((dataset) => (
                            <option key={getDatasetKey(dataset)} value={getDatasetKey(dataset)}>
                              {dataset.name}
                            </option>
                          ))}
                        </select>
                      </label>

                      {onDatasetColorChange && (
                        <label className="flex items-center justify-between gap-2 text-[11px] text-slate-600">
                          <span className="truncate">Color</span>
                          <input
                            type="color"
                            value={selectedEditDataset.color}
                            onChange={(e) => onDatasetColorChange(getDatasetKey(selectedEditDataset), e.target.value)}
                            className="h-6 w-8 rounded border border-slate-200 bg-white p-0 cursor-pointer"
                            title={`Set ${selectedEditDataset.name} color`}
                          />
                        </label>
                      )}

                      {onDatasetStyleChange && selectedEditDataset.type === "line" && (
                        <div className="rounded-lg border border-slate-100 p-2">
                          <div className="text-xs font-medium text-slate-600 truncate mb-2">Style</div>
                          <div className="grid grid-cols-2 gap-2">
                            <label className="text-[11px] text-slate-500">
                              <span className="block mb-1">Line</span>
                              <select
                                value={selectedEditDataset.lineStyle ?? "solid"}
                                onChange={(e) =>
                                  onDatasetStyleChange(getDatasetKey(selectedEditDataset), {
                                    lineStyle: e.target.value as "solid" | "dashed",
                                  })
                                }
                                className="w-full rounded-md border border-slate-200 bg-white px-2 py-1 text-xs text-slate-700"
                              >
                                <option value="solid">Solid</option>
                                <option value="dashed">Dashed</option>
                              </select>
                            </label>
                            <label className="text-[11px] text-slate-500">
                              <span className="block mb-1">Points</span>
                              <select
                                value={selectedEditDataset.pointStyle ?? "circle"}
                                onChange={(e) =>
                                  onDatasetStyleChange(getDatasetKey(selectedEditDataset), {
                                    pointStyle: e.target.value as "circle" | "square" | "none",
                                  })
                                }
                                className="w-full rounded-md border border-slate-200 bg-white px-2 py-1 text-xs text-slate-700"
                              >
                                <option value="circle">Circle</option>
                                <option value="square">Square</option>
                                <option value="none">None</option>
                              </select>
                            </label>
                          </div>
                        </div>
                      )}
                    </div>
                  </>
                )}

                {standardDatasets.some((dataset) => dataset.refMin !== undefined || dataset.refMax !== undefined) && (
                  <>
                    <div className="h-px bg-slate-100 my-1" />
                    <div className="px-2 py-2">
                      <label className="flex items-center gap-2 text-xs text-slate-600 cursor-pointer hover:text-slate-700">
                        <input
                          type="checkbox"
                          checked={normalizeByReference}
                          onChange={(e) => onNormalizeByReferenceChange?.(e.target.checked)}
                          className="rounded border-slate-200 cursor-pointer"
                        />
                        <span>Normalize by Reference</span>
                      </label>
                      <p className="text-[10px] text-slate-400 mt-1 pl-5">Scale datasets to reference range</p>
                    </div>
                  </>
                )}

                <div className="h-px bg-slate-100 my-1" />
                <button
                  type="button"
                  onClick={handleExport}
                  className="w-full flex items-center gap-2 px-3 py-2 text-sm text-slate-600 hover:bg-slate-50 rounded-lg text-left"
                >
                  <Download size={14} />
                  Export PNG
                </button>
              </div>
            </>
          )}
        </div>
      </div>

      <div className="flex-1 w-full min-h-0 relative z-10">
        <ChartCanvas
          id={id}
          datasets={datasets}
          mergedData={mergedData}
          xAxisDomain={xAxisDomain}
          normalizeByReference={normalizeByReference}
          seriesAnimationDuration={seriesAnimationDuration}
        />
      </div>
    </div>
  );
}
