/**
 * 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, Legend, ReferenceLine, ResponsiveContainer } from 'recharts';

// 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: '#9ca3af', // gray-400
  therapeuticMin: '#22c55e',  // green-500
  therapeuticMax: '#ef4444',  // red-500
  dayDivider: '#9ca3af',      // gray-400

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

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

  // Dynamically calculate tick interval based on displayed days
  // Aim for ~40-50 pixels per tick for readability
  const xTickInterval = React.useMemo(() => {
    // Scale interval with displayed days: 1 day = 1h, 2 days = 2h, 3-4 days = 3h, 5+ days = 6h
    if (dispDays <= 1) return 1;
    if (dispDays <= 2) return 2;
    if (dispDays <= 4) return 3;
    if (dispDays <= 6) return 4;
    return 6;
  }, [dispDays]);

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

  const chartDomain = 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);
        }
      });

      // Add small padding (5% on each side) for better visualization
      const range = dataMax - dataMin;
      const padding = range * 0.05;
      dataMin = Math.max(0, dataMin - padding); // Don't go below 0
      dataMax = dataMax + padding;
    }

    const domainMin = !isNaN(numMin) ? numMin : (dataMin !== Infinity ? Math.floor(dataMin) : 0);
    const domainMax = !isNaN(numMax) ? numMax : (dataMax !== -Infinity ? Math.ceil(dataMax) : 100);

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

  // Check which days have deviations (differ from template)
  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 template)
    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) => {
    if (dayNumber === 1) return t('refLineRegularPlan');

    // Check if this day has an actual schedule entry (not auto-filled)
    const hasSchedule = days && days.length >= dayNumber;

    // Check if this day deviates from template
    const hasDeviation = daysWithDeviations.has(dayNumber);

    if (!hasDeviation) {
      // Matches template
      return t('refLineNoDeviation');
    } else if (!hasSchedule) {
      // Deviates but no schedule = recovering
      return t('refLineRecovering');
    } else {
      // Has deviation and has schedule = actual irregular intake
      return t('refLineIrregularIntake');
    }
  }, [days, daysWithDeviations, t]);

  // 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]);

  // Calculate chart dimensions
  const [containerWidth, setContainerWidth] = React.useState(1000);
  const containerRef = React.useRef<HTMLDivElement>(null);

  React.useEffect(() => {
    const updateWidth = () => {
      if (containerRef.current) {
        setContainerWidth(containerRef.current.clientWidth);
      }
    };

    updateWidth();
    window.addEventListener('resize', updateWidth);
    return () => window.removeEventListener('resize', updateWidth);
  }, []);

  const simDays = parseInt(simulationDays, 10) || 3;

  // Y-axis takes ~80px, scrollable area gets the rest
  const yAxisWidth = 80;
  const scrollableWidth = containerWidth - yAxisWidth;

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

  return (
    <div ref={containerRef} className="flex-grow w-full flex flex-col overflow-y-hidden">
      {/* Fixed Legend at top */}
      <div style={{ height: 40, marginBottom: 8, paddingLeft: yAxisWidth + 10 }}>
        <ResponsiveContainer width="100%" height="100%">
          <LineChart data={mergedData} margin={{ top: 0, right: 20, left: 0, bottom: 0 }}>
            <Legend
              verticalAlign="top"
              align="left"
              height={36}
              wrapperStyle={{ paddingLeft: 0 }}
              formatter={(value: string) => {
                // Apply lighter color to template overlay entries in legend
                const isTemplate = value.includes(t('regularPlanOverlay'));
                return <span style={{ opacity: isTemplate ? 0.5 : 1 }}>{value}</span>;
              }}
            />
            {/* Invisible lines just to show in legend */}
            {(chartView === 'damph' || chartView === 'both') && (
              <Line
                dataKey="combinedDamph"
                name={`${t('dAmphetamine')}`}
                stroke={CHART_COLORS.idealDamph}
                strokeWidth={2.5}
                dot={false}
                strokeOpacity={0}
              />
            )}
            {(chartView === 'ldx' || chartView === 'both') && (
              <Line
                dataKey="combinedLdx"
                name={`${t('lisdexamfetamine')}`}
                stroke={CHART_COLORS.idealLdx}
                strokeWidth={2}
                strokeDasharray="3 3"
                dot={false}
                strokeOpacity={0}
              />
            )}
            {templateProfile && daysWithDeviations.size > 0 && (chartView === 'damph' || chartView === 'both') && (
              <Line
                dataKey="templateDamph"
                name={`${t('dAmphetamine')} (${t('regularPlanOverlay')})`}
                stroke={CHART_COLORS.idealDamph}
                strokeWidth={2}
                strokeDasharray="3 3"
                dot={false}
                strokeOpacity={0}
                opacity={0.5}
              />
            )}
            {templateProfile && daysWithDeviations.size > 0 && (chartView === 'ldx' || chartView === 'both') && (
              <Line
                dataKey="templateLdx"
                name={`${t('lisdexamfetamine')} (${t('regularPlanOverlay')})`}
                stroke={CHART_COLORS.idealLdx}
                strokeWidth={1.5}
                strokeDasharray="3 3"
                dot={false}
                strokeOpacity={0}
                opacity={0.5}
              />
            )}
          </LineChart>
        </ResponsiveContainer>
      </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 */}
            {(() => {
              const CustomTick = (props: any) => {
                const { x, y, payload } = props;
                const h = payload.value as number;
                let label: string;
                if (showDayTimeOnXAxis === '24h') {
                  label = `${h % 24}h`;
                } 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="#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="#666">
                    {label}
                  </text>
                );
              };
              return <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]}
                ticks={chartTicks}
                tickCount={chartTicks.length}
                interval={0}
                tick={<CustomTick />}
              />;
            })()}

            <YAxis
              yAxisId="concentration"
              // FIXME
              //label={{ value: t('axisLabelConcentration'), angle: -90, position: 'insideLeft', style: { fontStyle: 'italic', color: '#666' } }}
              domain={chartDomain as any}
              allowDecimals={false}
              tickCount={20}
            />
            <Tooltip
              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="recharts-default-tooltip" style={{ margin: 0, padding: 10, backgroundColor: 'rgb(255, 255, 255)', border: '1px solid rgb(204, 204, 204)', whiteSpace: 'nowrap' }}>
                    <p className="recharts-tooltip-label" style={{ margin: 0 }}>{t('time')}: {timeLabel}</p>
                    <ul className="recharts-tooltip-item-list" style={{ padding: 0, margin: 0 }}>
                      {payload.map((entry: any, index: number) => {
                        const isTemplate = entry.name?.includes(t('regularPlanOverlay'));
                        const opacity = isTemplate ? 0.5 : 1;
                        const value = typeof entry.value === 'number' ? entry.value.toFixed(1) : entry.value;

                        return (
                          <li key={`item-${index}`} className="recharts-tooltip-item" style={{ display: 'block', paddingTop: 4, paddingBottom: 4, color: entry.color, opacity }}>
                            <span className="recharts-tooltip-item-name">{entry.name}</span>
                            <span className="recharts-tooltip-item-separator">: </span>
                            <span className="recharts-tooltip-item-value">{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" />

            {showDayReferenceLines !== false && [...Array(dispDays+1).keys()].map(day => (
              <ReferenceLine
                key={`day-${day+1}`}
                x={24 * (day+1)}
                label={{
                  value: t('refLineDayX', { x: day+1 }) + ' ' + getDayLabel(day + 1),
                  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') && (
              <ReferenceLine
                y={parseFloat(therapeuticRange.min) || 0}
                label={{ value: t('refLineMin'), position: 'insideTopLeft' }}
                stroke={CHART_COLORS.therapeuticMin}
                strokeDasharray="3 3"
                xAxisId="hours"
                yAxisId="concentration"
              />
            )}
            {showTherapeuticRange && (chartView === 'damph' || chartView === 'both') && (
              <ReferenceLine
                y={parseFloat(therapeuticRange.max) || 0}
                label={{ value: t('refLineMax'), position: 'insideTopLeft' }}
                stroke={CHART_COLORS.therapeuticMax}
                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={`${t('dAmphetamine')}`}
                stroke={CHART_COLORS.idealDamph}
                strokeWidth={2.5}
                dot={false}
                xAxisId="hours"
                yAxisId="concentration"
                connectNulls
              />
            )}
            {(chartView === 'ldx' || chartView === 'both') && (
              <Line
                type="monotone"
                dataKey="combinedLdx"
                name={`${t('lisdexamfetamine')}`}
                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={`${t('dAmphetamine')} (${t('regularPlanOverlay')})`}
                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={`${t('lisdexamfetamine')} (${t('regularPlanOverlay')})`}
                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>
  );
};

export default SimulationChart;
