/**
 * Simulation Chart Component
 *
 * Visualizes pharmacokinetic concentration profiles over time using Recharts.
 * Displays ideal plan, deviated profile, and corrected profile with
 * therapeutic range indicators. Supports multiple chart views and x-axis formats.
 *
 * @author Andreas Weyer
 * @license MIT
 */

import React from 'react';
import {
  LineChart,
  Line,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip as RechartsTooltip,
  Legend,
  ReferenceLine,
  ResponsiveContainer,
} from 'recharts';
import {
  Tooltip as UiTooltip,
  TooltipTrigger as UiTooltipTrigger,
  TooltipContent as UiTooltipContent,
} from './ui/tooltip';
import { useElementSize } from '../hooks/useElementSize';

// TODO make use of the actual theme colors;some colors are not matching the classes in the comments
// Chart color scheme
const CHART_COLORS = {
  // d-Amphetamine profiles
  idealDamph: '#2563eb',      // blue-600 (primary, solid, bold)
  deviatedDamph: '#f59e0b',   // amber-500 (warning, dashed)
  correctedDamph: '#10b981',  // emerald-500 (success, dash-dot)

  // Lisdexamfetamine profiles
  idealLdx: '#7c3aed',        // violet-600 (primary, dashed)
  deviatedLdx: '#f97316',     // orange-500 (warning, dashed)
  correctedLdx: '#059669',    // emerald-600 (success, dash-dot)

  // Reference lines
  regularPlanDivider: '#22c55e',  // green-500
  deviationDayDivider: '#f59e0b', // yellow-500
  therapeuticMin: '#22c55e',  // green-500
  therapeuticMax: '#ef4444',  // red-500
  dayDivider: '#9ca3af',      // gray-400

  // Tooltip cursor
  cursor: '#6b7280'           // gray-500
} as const;

const SimulationChart = React.memo(({
  combinedProfile,
  templateProfile,
  chartView,
  showDayTimeOnXAxis,
  showDayReferenceLines,
  showIntakeTimeLines,
  showTherapeuticRange,
  therapeuticRange,
  simulationDays,
  displayedDays,
  yAxisMin,
  yAxisMax,
  days,
  t
}: any) => {
  const totalHours = (parseInt(simulationDays, 10) || 3) * 24;
  const dispDays = parseInt(displayedDays, 10) || 2;
  const simDays = parseInt(simulationDays, 10) || 3;

  // Calculate chart dimensions using debounced element size observer
  const containerRef = React.useRef<HTMLDivElement>(null);
  const { width: containerWidth } = useElementSize(containerRef, 150);

  // Guard against invalid dimensions during initial render
  const yAxisWidth = 80;
  const minContainerWidth = yAxisWidth + 100; // Minimum 100px for chart area
  const safeContainerWidth = Math.max(containerWidth, minContainerWidth);

  // Track current theme for chart styling
  const [isDarkTheme, setIsDarkTheme] = React.useState(false);

  React.useEffect(() => {
    const checkTheme = () => {
      setIsDarkTheme(document.documentElement.classList.contains('dark'));
    };

    checkTheme();

    // Use MutationObserver to detect theme changes
    const observer = new MutationObserver(checkTheme);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });

    return () => observer.disconnect();
  }, []);

  // Calculate scrollable width using safe container width
  const scrollableWidth = safeContainerWidth - yAxisWidth;

  // Calculate chart width for scrollable area
  const chartWidth = simDays <= dispDays
    ? scrollableWidth
    : Math.ceil((scrollableWidth / dispDays) * simDays);

  // Use shorter captions on narrow containers to reduce wrapping
  const isCompactLabels = safeContainerWidth < 640; // tweakable threshold for mobile

  // Precompute series labels with translations
  const seriesLabels = React.useMemo<Record<string, { full: string; short: string; display: string }>>(() => {
    const damphFull = t('dAmphetamine');
    const damphShort = t('dAmphetamineShort', { defaultValue: damphFull });
    const ldxFull = t('lisdexamfetamine');
    const ldxShort = t('lisdexamfetamineShort', { defaultValue: ldxFull });
    const overlayFull = t('regularPlanOverlay');
    const overlayShort = t('regularPlanOverlayShort', { defaultValue: overlayFull });

    const useShort = isCompactLabels;

    return {
      combinedDamph: {
        full: damphFull,
        short: damphShort,
        display: useShort ? damphShort : damphFull,
      },
      combinedLdx: {
        full: ldxFull,
        short: ldxShort,
        display: useShort ? ldxShort : ldxFull,
      },
      templateDamph: {
        full: `${damphFull} (${overlayFull})`,
        short: `${damphShort} (${overlayShort})`,
        display: useShort ? `${damphShort} (${overlayShort})` : `${damphFull} (${overlayFull})`,
      },
      templateLdx: {
        full: `${ldxFull} (${overlayFull})`,
        short: `${ldxShort} (${overlayShort})`,
        display: useShort ? `${ldxShort} (${overlayShort})` : `${ldxFull} (${overlayFull})`,
      },
    };
  }, [isCompactLabels, t]);

  // Dynamically calculate tick interval based on available pixel width
  const xTickInterval = React.useMemo(() => {
      // Aim for ~46px per label to avoid overlaps on narrow screens
    //const MIN_PX_PER_TICK = 46;
    const MIN_PX_PER_TICK = 46;
    const intervals = [1, 2, 3, 4, 6, 8, 12, 24];

    const pxPerDay = scrollableWidth / Math.max(1, dispDays);
    const ticksPerDay = Math.floor(pxPerDay / MIN_PX_PER_TICK);

    // Plenty of room: allow hourly ticks
    if (ticksPerDay >= 16) return 1;
    // Extremely tight: show one tick per day boundary
    if (ticksPerDay <= 0) return 24;

    const idealInterval = 24 / ticksPerDay;
    const selected = intervals.find((value) => value >= idealInterval);
    return selected ?? 24;
  }, [dispDays, scrollableWidth]);

  // Generate x-axis ticks for continuous time axis
  const xAxisTicks = React.useMemo(() => {
    const ticks = [];
    for (let i = 0; i <= totalHours; i += xTickInterval) {
      ticks.push(i);
    }
    return ticks;
  }, [totalHours, xTickInterval]);

  // Custom tick renderer for x-axis to handle 12h/24h/continuous formats and dark mode
  // Memoized to prevent unnecessary re-renders
  const XAxisTick = React.useCallback((props: any) => {
    const { x, y, payload } = props;
    const h = payload.value as number;
    let label: string;
    if (showDayTimeOnXAxis === '24h') {
      label = `${h % 24}${t('unitHour')}`;
    } else if (showDayTimeOnXAxis === '12h') {
      const hour12 = h % 24;
      if (hour12 === 12) {
        label = t('tickNoon');
        return (
          <text x={x} y={y + 12} textAnchor="middle" fontStyle="italic" fill={isDarkTheme ? '#ccc' : '#666'}>
            {label}
          </text>
        );
      }
      const displayHour = hour12 === 0 ? 12 : hour12 > 12 ? hour12 - 12 : hour12;
      const period = hour12 < 12 ? 'a' : 'p';
      label = `${displayHour}${period}`;
    } else {
      label = `${h}`;
    }
    return (
      <text x={x} y={y + 12} textAnchor="middle" fill={isDarkTheme ? '#ccc' : '#666'}>
        {label}
      </text>
    );
  }, [showDayTimeOnXAxis, isDarkTheme, t]);

  // Custom tick renderer for y-axis to handle dark mode
  // Memoized to prevent unnecessary re-renders
  const YAxisTick = React.useCallback((props: any) => {
    const { x, y, payload } = props;
    return (
      <text x={x} y={y + 4} textAnchor="end" fill={isDarkTheme ? '#ccc' : '#666'}>
        {payload.value}
      </text>
    );
  }, [isDarkTheme]);

  // Calculate Y-axis domain based on data and user settings
  const yAxisDomain = React.useMemo(() => {
    const numMin = parseFloat(yAxisMin);
    const numMax = parseFloat(yAxisMax);

    // Calculate actual data range if auto is needed
    let dataMin = Infinity;
    let dataMax = -Infinity;

    if (isNaN(numMin) || isNaN(numMax)) {
      // Scan through combined profile data to find actual min/max
      combinedProfile?.forEach((point: any) => {
        if (chartView === 'damph' || chartView === 'both') {
          dataMin = Math.min(dataMin, point.damph);
          dataMax = Math.max(dataMax, point.damph);
        }
        if (chartView === 'ldx' || chartView === 'both') {
          dataMin = Math.min(dataMin, point.ldx);
          dataMax = Math.max(dataMax, point.ldx);
        }
      });

      // Also check template profile if shown
      templateProfile?.forEach((point: any) => {
        if (chartView === 'damph' || chartView === 'both') {
          dataMin = Math.min(dataMin, point.damph);
          dataMax = Math.max(dataMax, point.damph);
        }
        if (chartView === 'ldx' || chartView === 'both') {
          dataMin = Math.min(dataMin, point.ldx);
          dataMax = Math.max(dataMax, point.ldx);
        }
      });
    }

    // Calculate final domain min
    let domainMin: number;
    if (!isNaN(numMin)) { // max value provided via settings
      // User set yAxisMin explicitly
      domainMin = numMin;
    } else if (dataMin !== Infinity) { // data exists
      // Auto mode: add 10% padding below so the line is not flush with x-axis
      const range = dataMax - dataMin;
      const padding = range * 0.1;
      domainMin = Math.max(0, dataMin - padding);
    } else { // no data
      domainMin = 0;
    }

    // Calculate final domain max
    let domainMax: number;
    if (!isNaN(numMax)) { // max value provided via settings
      if (dataMax !== -Infinity) {
        // User set yAxisMax explicitly
        // Add padding to dataMax and use the higher of manual or (dataMax + padding)
        const range = dataMax - dataMin;
        const padding = range * 0.1;
        const dataMaxWithPadding = dataMax + padding;
        // Use manual max only if it's higher than dataMax + padding
        domainMax = Math.max(numMax, dataMaxWithPadding);
      } else {
        // No data, use manual max as-is
        domainMax = numMax;
      }
    } else if (dataMax !== -Infinity) { // data exists
      // Auto mode: add 10% padding above
      const range = dataMax - dataMin;
      const padding = range * 0.1;
      domainMax = dataMax + padding;
    } else { // no data
      domainMax = 100;
    }

    return [domainMin, domainMax];
  }, [yAxisMin, yAxisMax, combinedProfile, templateProfile, chartView]);

  // Check which days have deviations (differ from regular plan)
  const daysWithDeviations = React.useMemo(() => {
    if (!templateProfile || !combinedProfile) return new Set<number>();

    const deviatingDays = new Set<number>();
    const simDays = parseInt(simulationDays, 10) || 3;

    // Check each day starting from day 2 (day 1 is always regular plan)
    for (let day = 2; day <= simDays; day++) {
      const dayStartHour = (day - 1) * 24;
      const dayEndHour = day * 24;

      // Sample points in this day to check for differences
      // Check every hour in the day
      for (let hour = dayStartHour; hour < dayEndHour; hour++) {
        const combinedPoint = combinedProfile.find((p: any) => Math.abs(p.timeHours - hour) < 0.1);
        const templatePoint = templateProfile.find((p: any) => Math.abs(p.timeHours - hour) < 0.1);

        if (combinedPoint && templatePoint) {
          // Consider it different if values differ by more than 0.01 (tolerance for floating point)
          const damphDiff = Math.abs(combinedPoint.damph - templatePoint.damph);
          const ldxDiff = Math.abs(combinedPoint.ldx - templatePoint.ldx);

          if (damphDiff > 0.01 || ldxDiff > 0.01) {
            deviatingDays.add(day);
            break; // Found deviation in this day, no need to check more hours
          }
        }
      }
    }

    return deviatingDays;
  }, [combinedProfile, templateProfile, simulationDays]);

  // Determine label for each day's reference line
  const getDayLabel = React.useCallback((dayNumber: number, useShort = false) => {
    if (dayNumber === 1) return t(useShort ? 'refLineRegularPlanShort' : 'refLineRegularPlan');

    const hasSchedule = days && days.length >= dayNumber;
    const hasDeviation = daysWithDeviations.has(dayNumber);

    if (!hasDeviation) {
      return t(useShort ? 'refLineNoDeviationShort' : 'refLineNoDeviation');
    } else if (!hasSchedule) {
      return t(useShort ? 'refLineRecoveringShort' : 'refLineRecovering');
    } else {
      return t(useShort ? 'refLineIrregularIntakeShort' : 'refLineIrregularIntake');
    }
  }, [days, daysWithDeviations, t]);

  // Extract all intake times from all days for intake time reference lines
  const intakeTimes = React.useMemo(() => {
    if (!days || !Array.isArray(days)) return [];

    const times: Array<{ hour: number; dayIndex: number; doseIndex: number }> = [];
    const simDaysCount = parseInt(simulationDays, 10) || 3;

    // Iterate through each simulated day
    for (let dayNum = 1; dayNum <= simDaysCount; dayNum++) {
      // Determine which schedule to use for this day
      let daySchedule;
      if (dayNum === 1 || days.length === 1) {
        // First day or only one schedule exists: use template/first schedule
        daySchedule = days.find(d => d.isTemplate) || days[0];
      } else {
        // For subsequent days, use the corresponding schedule if it exists, otherwise use template
        const scheduleIndex = dayNum - 1;
        daySchedule = days[scheduleIndex] || days.find(d => d.isTemplate) || days[0];
      }

      if (daySchedule && daySchedule.doses) {
        daySchedule.doses.forEach((dose: any, doseIdx: number) => {
          if (dose.time) {
            const [hours, minutes] = dose.time.split(':').map(Number);
            const hoursSinceStart = (dayNum - 1) * 24 + hours + minutes / 60;
            times.push({
              hour: hoursSinceStart,
              dayIndex: dayNum,
              doseIndex: doseIdx + 1 // 1-based index
            });
          }
        });
      }
    }

    return times;
  }, [days, simulationDays]);

  // Merge all profiles into a single dataset for proper tooltip synchronization
  const mergedData = React.useMemo(() => {
    const dataMap = new Map();

    // Add combined profile data (actual plan with all days)
    combinedProfile?.forEach((point: any) => {
      dataMap.set(point.timeHours, {
        timeHours: point.timeHours,
        combinedDamph: point.damph,
        combinedLdx: point.ldx
      });
    });

    // Add template profile data (regular plan only) if provided
    // Only include points for days that have deviations
    templateProfile?.forEach((point: any) => {
      const pointDay = Math.ceil(point.timeHours / 24);

      // Only include template data for days with deviations
      if (daysWithDeviations.has(pointDay)) {
        const existing = dataMap.get(point.timeHours) || { timeHours: point.timeHours };
        dataMap.set(point.timeHours, {
          ...existing,
          templateDamph: point.damph,
          templateLdx: point.ldx
        });
      }
    });

    return Array.from(dataMap.values()).sort((a, b) => a.timeHours - b.timeHours);
  }, [combinedProfile, templateProfile, daysWithDeviations]);

  // Render legend with tooltips for full names (custom legend renderer)
  const renderLegend = React.useCallback((props: any) => {
    const { payload } = props;
    if (!payload) return null;

    return (
      <ul className="flex flex-wrap gap-2 text-xs leading-tight">
        {payload.map((item: any) => {
          const labelInfo = seriesLabels[item.dataKey] || { display: item.value, full: item.value };
          const opacity = item.payload?.opacity ?? 1;

          return (
            <li key={item.dataKey} className="flex items-center gap-1 max-w-[140px]">
              <span
                className="inline-block w-3 h-3 rounded-sm"
                style={{ backgroundColor: item.color, opacity }}
              />
              <UiTooltip>
                <UiTooltipTrigger asChild>
                  <span
                    className="px-1 py-0.5 rounded-sm bg-background text-foreground shadow-sm border border-border truncate inline-block max-w-[100px]"
                  >
                    {labelInfo.display}
                  </span>
                </UiTooltipTrigger>
                <UiTooltipContent className="bg-background text-foreground shadow-md border border-border max-w-xs">
                  <span className="font-medium">{labelInfo.full}</span>
                </UiTooltipContent>
              </UiTooltip>
            </li>
          );
        })}
      </ul>
    );
  }, [seriesLabels]);

  // Don't render chart if dimensions are invalid (prevents crash during initialization)
  if (chartWidth <= 0 || scrollableWidth <= 0) {
    return (
      <div ref={containerRef} className="flex-grow w-full flex flex-col overflow-y-hidden items-center justify-center text-muted-foreground">
        <p>{t('loadingChart', { defaultValue: 'Loading chart...' })}</p>
      </div>
    );
  }

  // Render the chart
  return (
    <div ref={containerRef} className="flex-grow w-full flex flex-col overflow-y-hidden">
      {/* Fixed Legend at top */}
      <div style={{ marginBottom: 8, paddingLeft: yAxisWidth + 10 }}>
        {renderLegend({
          payload: [
            ...(chartView === 'damph' || chartView === 'both'
              ? [
                  {
                    dataKey: 'combinedDamph',
                    value: seriesLabels.combinedDamph.display,
                    color: CHART_COLORS.idealDamph,
                    payload: { opacity: 1 },
                  },
                ]
              : []),
            ...(chartView === 'ldx' || chartView === 'both'
              ? [
                  {
                    dataKey: 'combinedLdx',
                    value: seriesLabels.combinedLdx.display,
                    color: CHART_COLORS.idealLdx,
                    payload: { opacity: 1 },
                  },
                ]
              : []),
            ...(templateProfile && daysWithDeviations.size > 0 && (chartView === 'damph' || chartView === 'both')
              ? [
                  {
                    dataKey: 'templateDamph',
                    value: seriesLabels.templateDamph.display,
                    color: CHART_COLORS.idealDamph,
                    payload: { opacity: 0.5 },
                  },
                ]
              : []),
            ...(templateProfile && daysWithDeviations.size > 0 && (chartView === 'ldx' || chartView === 'both')
              ? [
                  {
                    dataKey: 'templateLdx',
                    value: seriesLabels.templateLdx.display,
                    color: CHART_COLORS.idealLdx,
                    payload: { opacity: 0.5 },
                  },
                ]
              : []),
          ],
        })}
      </div>

      {/* Chart */}
      <div className="flex-grow flex overflow-y-hidden">
        {/* Scrollable chart area */}
        <div className="flex-grow overflow-x-auto overflow-y-hidden">
          <div style={{ width: chartWidth, height: '100%' }}>
            <ResponsiveContainer width="100%" height="100%">
              <LineChart
                data={mergedData}
                margin={{ top: 0, right: 20, left: 0, bottom: 5 }}
                syncId="medPlanChart"
              >
                {/** Custom tick renderer to italicize 'Noon' only in 12h mode */ }
            <XAxis
                xAxisId="hours"
                //label={{ value: showDayTimeOnXAxis === 'continuous' ? t('axisLabelHours') : t('axisLabelTimeOfDay'), position: 'insideBottom', offset: -10, style: { fontStyle: 'italic', color: '#666' } }}
                dataKey="timeHours"
                type="number"
                domain={[0, totalHours]}
                axisLine={{ stroke: isDarkTheme ? '#ccc' : '#666' }}
                tick={<XAxisTick />}
                ticks={xAxisTicks}
                tickCount={xAxisTicks.length}
                //tickCount={200}
                //interval={1}
                allowDecimals={false}
                allowDataOverflow={false}
              />
            <YAxis
              yAxisId="concentration"
              // FIXME
              //label={{ value: t('axisLabelConcentration'), angle: -90, position: 'insideLeft', style: { fontStyle: 'italic', color: '#666' } }}
              domain={yAxisDomain as any}
              axisLine={{ stroke: isDarkTheme ? '#ccc' : '#666' }}
              tick={<YAxisTick />}
              allowDecimals={true}
              allowDataOverflow={false}
            />
            <RechartsTooltip
              content={({ active, payload, label }) => {
                if (!active || !payload || payload.length === 0) return null;

                // Extract timeHours from the payload data point
                const timeHours = payload[0]?.payload?.timeHours ?? label;
                const h = typeof timeHours === 'number' ? timeHours : parseFloat(timeHours);

                // Format time to match x-axis format
                let timeLabel: string;
                if (showDayTimeOnXAxis === '24h') {
                  timeLabel = `${h % 24}${t('unitHour')}`;
                } else if (showDayTimeOnXAxis === '12h') {
                  const hour12 = h % 24;
                  if (hour12 === 12) {
                    timeLabel = t('tickNoon');
                  } else {
                    const displayHour = hour12 === 0 ? 12 : hour12 > 12 ? hour12 - 12 : hour12;
                    const period = hour12 < 12 ? 'a' : 'p';
                    timeLabel = `${displayHour}${period}`;
                  }
                } else {
                  timeLabel = `${h}${t('unitHour')}`;
                }

                return (
                  <div className="bg-background border border-border rounded shadow-lg" style={{ margin: 0, padding: 10, whiteSpace: 'nowrap' }}>
                    <p className="text-foreground font-medium" style={{ margin: 0 }}>{t('time')}: {timeLabel}</p>
                    <ul style={{ padding: 0, margin: 0 }}>
                      {payload.map((entry: any, index: number) => {
                        const labelInfo = seriesLabels[entry.dataKey] || { display: entry.name, full: entry.name };
                        const isTemplate = entry.dataKey?.toString().includes('template');
                        const opacity = isTemplate ? 0.5 : 1;
                        const value = typeof entry.value === 'number' ? entry.value.toFixed(1) : entry.value;

                        return (
                          <li
                            key={`item-${index}`}
                            className="text-foreground"
                            style={{ display: 'block', paddingTop: 4, paddingBottom: 4, color: entry.color, opacity }}
                          >
                            <span title={labelInfo.full}>{labelInfo.display}</span>
                            <span>: </span>
                            <span>{value} {t('unitNgml')}</span>
                          </li>
                        );
                      })}
                    </ul>
                  </div>
                );
              }}
              wrapperStyle={{ pointerEvents: 'none', zIndex: 200 }}
              allowEscapeViewBox={{ x: false, y: false }}
              cursor={{ stroke: CHART_COLORS.cursor, strokeWidth: 1, strokeDasharray: '1 1' }}
              position={{ y: 0 }}
            />
            <CartesianGrid strokeDasharray="1 1" xAxisId="hours" yAxisId="concentration"
                  style={{ stroke: isDarkTheme ? '#666' : '#ccc' }}
            />

            {showDayReferenceLines !== false && [...Array(dispDays + 1).keys()].map(day => {
              // Determine whether to use compact day labels to avoid overlap on narrow screens
              const pxPerDay = scrollableWidth / Math.max(1, dispDays);
              let label = "";
              if (pxPerDay < 75) { // tweakable threshold, minimal label
                label = t('refLineDayShort', { x: day + 1 });
              } else if (pxPerDay < 110) { // tweakable threshold, compact label
                label = t('refLineDayShort', { x: day + 1 }) + ' ' + getDayLabel(day + 1, true);
              } else { // full label
                label = t('refLineDayX', { x: day + 1 }) + ' ' + getDayLabel(day + 1);
              }
              return (
                <ReferenceLine
                  key={`day-${day + 1}`}
                  x={24 * (day + 1)}
                  label={{
                    value: `${label}`,
                    position: 'insideTopRight',
                    style: {
                      fontSize: '0.75rem',
                      fontStyle: 'italic',
                      fill: day === 0 ? CHART_COLORS.regularPlanDivider : CHART_COLORS.deviationDayDivider
                    }
                  }}
                  stroke={day === 0 ? CHART_COLORS.regularPlanDivider : CHART_COLORS.deviationDayDivider}
                  //strokeDasharray="0 0"
                  xAxisId="hours"
                  yAxisId="concentration"
                />
              );
            })}
            {showTherapeuticRange && (chartView === 'damph' || chartView === 'both') && therapeuticRange.min && !isNaN(parseFloat(therapeuticRange.min)) && (
              <ReferenceLine
                y={parseFloat(therapeuticRange.min)}
                label={{ value: t('refLineMin'), position: 'insideBottomLeft', style: { fontSize: '0.75rem', fontStyle: 'italic', fill: CHART_COLORS.therapeuticMin } }}
                stroke={CHART_COLORS.therapeuticMin}
                strokeDasharray="3 3"
                xAxisId="hours"
                yAxisId="concentration"
              />
            )}
            {showTherapeuticRange && (chartView === 'damph' || chartView === 'both') && therapeuticRange.max && !isNaN(parseFloat(therapeuticRange.max)) && (
              <ReferenceLine
                y={parseFloat(therapeuticRange.max)}
                label={{ value: t('refLineMax'), position: 'insideTopLeft', style: { fontSize: '0.75rem', fontStyle: 'italic', fill: CHART_COLORS.therapeuticMax } }}
                stroke={CHART_COLORS.therapeuticMax}
                strokeDasharray="3 3"
                xAxisId="hours"
                yAxisId="concentration"
              />
            )}

            {showIntakeTimeLines && intakeTimes.map((intake, idx) => {
              // Determine label position offset if day lines are also shown
              const labelOffsetY = showDayReferenceLines !== false ? 20 : 5; // More spacing when day lines are shown

              return (
                <ReferenceLine
                  key={`intake-${idx}`}
                  x={intake.hour}
                  label={(props: any) => {
                    const { viewBox } = props;
                    // Position at top-right of the reference line with proper offsets
                    // x: subtract 5px from right edge to create gap between line and text
                    // y: add offset + ~12px (font size) since y is the text baseline, not top
                    const x = viewBox.x + viewBox.width - 5;
                    const y = viewBox.y + labelOffsetY + 12; // 12px ≈ 0.75rem font size

                    return (
                      <text
                        x={x}
                        y={y}
                        textAnchor="end"
                        fontSize="0.75rem"
                        fontStyle="italic"
                        fill="#a0a0a0"
                      >
                        {intake.doseIndex}
                      </text>
                    );
                  }}
                  stroke="#c0c0c0"
                  strokeDasharray="3 3"
                  xAxisId="hours"
                  yAxisId="concentration"
                />
              );
            })}

            {[...Array(parseInt(simulationDays, 10) || 3).keys()].map(day => (
              day > 0 && (
                <ReferenceLine
                  key={day}
                  x={day * 24}
                  stroke={CHART_COLORS.dayDivider}
                  strokeDasharray="5 5"
                  xAxisId="hours"
                />
              )
            ))}

            {(chartView === 'damph' || chartView === 'both') && (
              <Line
                type="monotone"
                dataKey="combinedDamph"
                name={seriesLabels.combinedDamph.display}
                stroke={CHART_COLORS.idealDamph}
                strokeWidth={2.5}
                dot={false}
                xAxisId="hours"
                yAxisId="concentration"
                connectNulls
              />
            )}
            {(chartView === 'ldx' || chartView === 'both') && (
              <Line
                type="monotone"
                dataKey="combinedLdx"
                name={seriesLabels.combinedLdx.display}
                stroke={CHART_COLORS.idealLdx}
                strokeWidth={2}
                dot={false}
                strokeDasharray="3 3"
                xAxisId="hours"
                yAxisId="concentration"
                connectNulls
              />
            )}

            {templateProfile && (chartView === 'damph' || chartView === 'both') && (
              <Line
                type="monotone"
                dataKey="templateDamph"
                name={seriesLabels.templateDamph.display}
                stroke={CHART_COLORS.idealDamph}
                strokeWidth={2}
                strokeDasharray="3 3"
                dot={false}
                xAxisId="hours"
                yAxisId="concentration"
                connectNulls
                strokeOpacity={0.5}
              />
            )}
            {templateProfile && (chartView === 'ldx' || chartView === 'both') && (
              <Line
                type="monotone"
                dataKey="templateLdx"
                name={seriesLabels.templateLdx.display}
                stroke={CHART_COLORS.idealLdx}
                strokeWidth={1.5}
                strokeDasharray="3 3"
                dot={false}
                xAxisId="hours"
                yAxisId="concentration"
                connectNulls
                strokeOpacity={0.5}
              />
            )}
              </LineChart>
            </ResponsiveContainer>
          </div>
        </div>
      </div>
    </div>
  );
}, (prevProps, nextProps) => {
  // Custom comparison function to prevent unnecessary re-renders
  // Only re-render if relevant props actually changed
  return (
    prevProps.combinedProfile === nextProps.combinedProfile &&
    prevProps.templateProfile === nextProps.templateProfile &&
    prevProps.chartView === nextProps.chartView &&
    prevProps.showDayTimeOnXAxis === nextProps.showDayTimeOnXAxis &&
    prevProps.showDayReferenceLines === nextProps.showDayReferenceLines &&
    prevProps.showIntakeTimeLines === nextProps.showIntakeTimeLines &&
    prevProps.showTherapeuticRange === nextProps.showTherapeuticRange &&
    prevProps.therapeuticRange?.min === nextProps.therapeuticRange?.min &&
    prevProps.therapeuticRange?.max === nextProps.therapeuticRange?.max &&
    prevProps.simulationDays === nextProps.simulationDays &&
    prevProps.displayedDays === nextProps.displayedDays &&
    prevProps.yAxisMin === nextProps.yAxisMin &&
    prevProps.yAxisMax === nextProps.yAxisMax &&
    prevProps.days === nextProps.days
  );
});

SimulationChart.displayName = 'SimulationChart';

export default SimulationChart;
