/**
 * Day Schedule Component
 *
 * Manages day-based medication schedules with doses.
 * Allows adding/removing days, cloning days, and managing doses within each day.
 *
 * @author Andreas Weyer
 * @license MIT
 */

import React from 'react';
import { Button } from './ui/button';
import { Card, CardContent } from './ui/card';
import { Badge } from './ui/badge';
import { FormTimeInput } from './ui/form-time-input';
import { FormNumericInput } from './ui/form-numeric-input';
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
import { IconButtonWithTooltip } from './ui/icon-button-with-tooltip';
import CollapsibleCardHeader from './ui/collapsible-card-header';
import { Plus, Copy, Trash2, TrendingUp, TrendingDown, Utensils } from 'lucide-react';
import type { DayGroup } from '../constants/defaults';
import { MAX_DOSES_PER_DAY } from '../constants/defaults';
import { formatText } from '../utils/contentFormatter';

interface DayScheduleProps {
  days: DayGroup[];
  doseIncrement: string;
  onAddDay: (cloneFromDayId?: string) => void;
  onRemoveDay: (dayId: string) => void;
  onAddDose: (dayId: string) => void;
  onRemoveDose: (dayId: string, doseId: string) => void;
  onUpdateDose: (dayId: string, doseId: string, field: 'time' | 'ldx' | 'damph', value: string) => void;
  onUpdateDoseField: (dayId: string, doseId: string, field: string, value: any) => void; // For non-string fields like isFed
  onSortDoses: (dayId: string) => void;
  t: any;
}

const DaySchedule: React.FC<DayScheduleProps> = ({
  days,
  doseIncrement,
  onAddDay,
  onRemoveDay,
  onAddDose,
  onRemoveDose,
  onUpdateDose,
  onUpdateDoseField,
  onSortDoses,
  t
}) => {
  const canAddDay = days.length < 3;

  // Track collapsed state for each day (by day ID)
  const [collapsedDays, setCollapsedDays] = React.useState<Set<string>>(new Set());

  // Track pending sort timeouts for debounced sorting
  const [pendingSorts, setPendingSorts] = React.useState<Map<string, NodeJS.Timeout>>(new Map());

  // Schedule a debounced sort for a day
  const scheduleSort = React.useCallback((dayId: string) => {
    // Cancel any existing pending sort for this day
    const existingTimeout = pendingSorts.get(dayId);
    if (existingTimeout) {
      clearTimeout(existingTimeout);
    }

    // Schedule new sort after delay
    const timeoutId = setTimeout(() => {
      onSortDoses(dayId);
      setPendingSorts(prev => {
        const newMap = new Map(prev);
        newMap.delete(dayId);
        return newMap;
      });
    }, 100);

    setPendingSorts(prev => {
      const newMap = new Map(prev);
      newMap.set(dayId, timeoutId);
      return newMap;
    });
  }, [pendingSorts, onSortDoses]);

  // Handle time field blur - schedule a sort
  const handleTimeBlur = React.useCallback((dayId: string) => {
    scheduleSort(dayId);
  }, [scheduleSort]);

  // Wrap action handlers to cancel pending sorts and execute action, then sort
  const handleActionWithSort = React.useCallback((dayId: string, action: () => void) => {
    // Cancel pending sort
    const pendingTimeout = pendingSorts.get(dayId);
    if (pendingTimeout) {
      clearTimeout(pendingTimeout);
      setPendingSorts(prev => {
        const newMap = new Map(prev);
        newMap.delete(dayId);
        return newMap;
      });
    }

    // Execute the action
    action();

    // Schedule sort after action completes
    setTimeout(() => {
      onSortDoses(dayId);
    }, 50);
  }, [pendingSorts, onSortDoses]);

  // Clean up pending timeouts on unmount
  React.useEffect(() => {
    return () => {
      pendingSorts.forEach(timeout => clearTimeout(timeout));
    };
  }, [pendingSorts]);

  // Calculate time delta from previous intake (across all days)
  const calculateTimeDelta = (dayIndex: number, doseIndex: number): string => {
    if (dayIndex === 0 && doseIndex === 0) {
      return ""; // No delta for first dose of first day
    }

    const currentDay = days[dayIndex];
    const currentDose = currentDay.doses[doseIndex];

    if (!currentDose.time) return '';

    const [currHours, currMinutes] = currentDose.time.split(':').map(Number);
    const currentTotalMinutes = (dayIndex * 24 * 60) + (currHours * 60) + currMinutes;

    let prevTotalMinutes = 0;

    // Find previous dose
    if (doseIndex > 0) {
      // Previous dose is in the same day
      const prevDose = currentDay.doses[doseIndex - 1];
      if (prevDose.time) {
        const [prevHours, prevMinutes] = prevDose.time.split(':').map(Number);
        prevTotalMinutes = (dayIndex * 24 * 60) + (prevHours * 60) + prevMinutes;
      }
    } else if (dayIndex > 0) {
      // Previous dose is the last dose of the previous day
      const prevDay = days[dayIndex - 1];
      if (prevDay.doses.length > 0) {
        const lastDoseOfPrevDay = prevDay.doses[prevDay.doses.length - 1];
        if (lastDoseOfPrevDay.time) {
          const [prevHours, prevMinutes] = lastDoseOfPrevDay.time.split(':').map(Number);
          prevTotalMinutes = ((dayIndex - 1) * 24 * 60) + (prevHours * 60) + prevMinutes;
        }
      }
    }

    const deltaMinutes = currentTotalMinutes - prevTotalMinutes;
    const deltaHours = Math.floor(deltaMinutes / 60);
    const remainingMinutes = deltaMinutes % 60;

    return `+${deltaHours}:${remainingMinutes.toString().padStart(2, '0')}`;
  };

  // Calculate dose index across all days
  const getDoseGlobalIndex = (dayIndex: number, doseIndex: number): number => {
    let globalIndex = 1;

    for (let d = 0; d < dayIndex; d++) {
      globalIndex += days[d].doses.length;
    }

    globalIndex += doseIndex + 1;
    return globalIndex;
  };

  // Load and persist collapsed days state
  React.useEffect(() => {
    const savedCollapsed = localStorage.getItem('dayScheduleCollapsedDays_v1');
    if (savedCollapsed) {
      try {
        const collapsedArray = JSON.parse(savedCollapsed);
        setCollapsedDays(new Set(collapsedArray));
      } catch (e) {
        console.warn('Failed to load collapsed days state:', e);
      }
    }
  }, []);

  const saveCollapsedDays = (newCollapsedDays: Set<string>) => {
    localStorage.setItem('dayScheduleCollapsedDays_v1', JSON.stringify(Array.from(newCollapsedDays)));
  };

  const toggleDayCollapse = (dayId: string) => {
    setCollapsedDays(prev => {
      const newSet = new Set(prev);
      if (newSet.has(dayId)) {
        newSet.delete(dayId);
      } else {
        newSet.add(dayId);
      }
      saveCollapsedDays(newSet);
      return newSet;
    });
  };


  return (
    <div className="space-y-4">
      {days.map((day, dayIndex) => {
        // Get template day for comparison
        const templateDay = days.find(d => d.isTemplate);

        // Calculate daily total
        const dayTotal = day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0);

        // Check for daily total warnings/errors
        const isDailyTotalError = dayTotal > 200;
        const isDailyTotalWarning = !isDailyTotalError && dayTotal > 70;

        // Calculate differences for deviation days
        let doseCountDiff = 0;
        let totalMgDiff = 0;

        if (!day.isTemplate && templateDay) {
          doseCountDiff = day.doses.length - templateDay.doses.length;
          const templateTotal = templateDay.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0);
          totalMgDiff = dayTotal - templateTotal;
        }

        // FIXME incomplete implementation of @container and @min-[497px]:
        // TODO solution not ideal for mobile, consider https://tailwindcss.com/docs/responsive-design
        return (
          <Card key={day.id} className="@container">
            <CollapsibleCardHeader
              title={day.isTemplate ? t('regularPlan') : t('alternativePlan')}
              isCollapsed={collapsedDays.has(day.id)}
              onToggle={() => toggleDayCollapse(day.id)}
              toggleLabel={collapsedDays.has(day.id) ? t('expandDay') : t('collapseDay')}
              rightSection={
                <>
                  {canAddDay && (
                    <IconButtonWithTooltip
                      onClick={() => onAddDay(day.id)}
                      icon={<Copy className="h-4 w-4" />}
                      tooltip={t('cloneDay')}
                      size="sm"
                      variant="outline"
                    />
                  )}
                  {!day.isTemplate && (
                    <IconButtonWithTooltip
                      onClick={() => onRemoveDay(day.id)}
                      icon={<Trash2 className="h-4 w-4" />}
                      tooltip={t('removeDay')}
                      size="sm"
                      variant="outline"
                      className="text-destructive hover:bg-destructive hover:text-destructive-foreground"
                    />
                  )}
                </>
              }
            >
              <div className="flex flex-nowrap items-center gap-2">
                <Badge variant="solid" className="text-xs font-bold">
                  {t('day')} {dayIndex + 1}
                </Badge>
                {!day.isTemplate && doseCountDiff !== 0 ? (
                  <Tooltip>
                    <TooltipTrigger asChild>
                      <button
                        type="button"
                        className="inline-flex items-center cursor-help focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 rounded-md"
                      >
                        <Badge
                          variant="outline"
                          className={`text-xs ${doseCountDiff > 0 ? 'badge-trend-up' : 'badge-trend-down'}`}
                        >
                          {doseCountDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />}
                          {day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')}
                        </Badge>
                      </button>
                    </TooltipTrigger>
                    <TooltipContent>
                      <p className="text-xs">
                        {doseCountDiff > 0 ? '+' : ''}{doseCountDiff} {Math.abs(doseCountDiff) === 1 ? t('dose') : t('doses')} {t('comparedToRegularPlan')}
                      </p>
                    </TooltipContent>
                  </Tooltip>
                ) : (
                  <Badge variant="outline" className="text-xs">
                    {day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')}
                  </Badge>
                )}
                {!day.isTemplate && Math.abs(totalMgDiff) > 0.1 ? (
                  <Tooltip>
                    <TooltipTrigger asChild>
                      <button
                        type="button"
                        className="inline-flex items-center cursor-help focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 rounded-md"
                      >
                        <Badge
                          variant="outline"
                          className={`text-xs ${
                            isDailyTotalError
                              ? 'badge-error'
                              : isDailyTotalWarning
                                ? 'badge-warning'
                                : totalMgDiff > 0
                                  ? 'badge-trend-up'
                                  : 'badge-trend-down'
                          }`}
                        >
                          {!isDailyTotalError && !isDailyTotalWarning && (totalMgDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />)}
                          {dayTotal.toFixed(1)} mg
                        </Badge>
                      </button>
                    </TooltipTrigger>
                    <TooltipContent>
                      <p className="text-xs">
                        {isDailyTotalError
                          ? `${t('errorDailyTotalAbove200mg').replace('{{total}}', dayTotal.toFixed(1))}`
                          : isDailyTotalWarning
                            ? `${t('warningDailyTotalAbove70mg').replace('{{total}}', dayTotal.toFixed(1))}`
                            : `${totalMgDiff > 0 ? '+' : ''}${totalMgDiff.toFixed(1)} mg ${t('comparedToRegularPlan')}`
                        }
                      </p>
                    </TooltipContent>
                  </Tooltip>
                ) : (
                  <Badge
                    variant="outline"
                    className={`text-xs ${
                      isDailyTotalError
                        ? 'badge-error'
                        : isDailyTotalWarning
                          ? 'badge-warning'
                          : ''
                    }`}
                  >
                    {dayTotal.toFixed(1)} mg
                  </Badge>
                )}
              </div>
            </CollapsibleCardHeader>

            {/* Daily details (intakes) */}
            {!collapsedDays.has(day.id) && (
            <CardContent className="space-y-3">
              {/* Daily total warning/error box */}
              {(isDailyTotalWarning || isDailyTotalError) && (
                <div className={`p-3 rounded-md text-sm ${isDailyTotalError ? 'error-bg-box' : 'warning-bg-box'}`}>

                      {formatText(isDailyTotalError
                        ? t('errorDailyTotalAbove200mg').replace('{{total}}', dayTotal.toFixed(1))
                        : t('warningDailyTotalAbove70mg').replace('{{total}}', dayTotal.toFixed(1))
                      )}
                </div>
              )}
              {/* Dose table header */}
              <div className="grid items-center gap-0.5 text-sm font-medium text-muted-foreground" style={{gridTemplateColumns: '20px 172px 72px 1fr'}}>
                <div className="flex justify-center">#</div>{/* Index header */}
                <div>{t('time')}</div>{/* Time header */}
                <div>{t('ldx')} (mg)</div>{/* LDX header */}
                <div></div>{/* Buttons column (empty header) */}
              </div>

              {/* Dose rows */}
              {day.doses.map((dose, doseIdx) => {
                // Check for duplicate times
                const duplicateTimeCount = day.doses.filter(d => d.time === dose.time).length;
                const hasDuplicateTime = duplicateTimeCount > 1;

                // Check for zero dose
                const isZeroDose = dose.ldx === '0' || dose.ldx === '0.0';
                // Check for dose > 70 mg
                const isHighDose = parseFloat(dose.ldx) > 70;

                // Determine the error/warning message priority:
                // 1. Daily total error (> 200mg) - ERROR
                // 2. Daily total warning (> 70mg) - WARNING
                // 3. Individual dose warning (zero dose or > 70mg) - WARNING
                let doseErrorMessage;
                let doseWarningMessage;

                if (isDailyTotalError) {
                  doseErrorMessage = formatText(t('errorDailyTotalAbove200mg').replace('{{total}}', dayTotal.toFixed(1)));
                } else if (isDailyTotalWarning) {
                  doseWarningMessage = formatText(t('warningDailyTotalAbove70mg').replace('{{total}}', dayTotal.toFixed(1)));
                } else if (isZeroDose) {
                  doseWarningMessage = formatText(t('warningZeroDose'));
                } else if (isHighDose) {
                  doseWarningMessage = formatText(t('warningDoseAbove70mg'));
                }

                const timeDelta = calculateTimeDelta(dayIndex, doseIdx);
                const doseIndex = doseIdx + 1;

                return (
                  <div key={dose.id} className="space-y-2">
                    <div className="grid items-center gap-0.5" style={{gridTemplateColumns: '20px 172px 72px 1fr'}}>
                      {/* Intake index badge */}
                      <div className="flex justify-center">
                        <Badge variant="solid"
                          className="text-xs w-5 h-6 flex items-center justify-center px-1.5">
                          {doseIndex}
                        </Badge>
                      </div>

                      {/* Time input with delta badge attached (where applicable) */}
                      <div className="flex flex-nowrap items-center justify-center gap-0">
                        <FormTimeInput
                          value={dose.time}
                          onChange={(value) => onUpdateDose(day.id, dose.id, 'time', value)}
                          onBlur={() => handleTimeBlur(day.id)}
                          required={true}
                          warning={hasDuplicateTime}
                          errorMessage={formatText(t('errorTimeRequired'))}
                          warningMessage={formatText(t('warningDuplicateTime'))}
                        />
                        <Badge variant={timeDelta ? "field" : "transparent"} className="rounded-l-none border-l-0 font-light italic text-muted-foreground text-xs w-12 h-6 flex justify-end px-1.5">
                          {timeDelta}
                        </Badge>
                      </div>

                      {/* LDX dose input */}
                      <FormNumericInput
                        value={dose.ldx}
                        onChange={(value) => onUpdateDose(day.id, dose.id, 'ldx', value)}
                        increment={doseIncrement}
                        min={0}
                        max={200}
                        //unit="mg"
                        required={true}
                        error={isDailyTotalError}
                        warning={isDailyTotalWarning || isZeroDose || isHighDose}
                        errorMessage={doseErrorMessage || formatText(t('errorNumberRequired'))}
                        warningMessage={doseWarningMessage}
                        inputWidth="w-[72px]"
                      />

                      {/* Action buttons - right aligned */}
                      <div className="flex flex-nowrap items-center justify-end gap-1">
                        <IconButtonWithTooltip
                          onClick={() => handleActionWithSort(day.id, () => onUpdateDoseField(day.id, dose.id, 'isFed', !dose.isFed))}
                          icon={<Utensils className="h-4 w-4" />}
                          tooltip={dose.isFed ? t('doseWithFood') : t('doseFasted')}
                          size="sm"
                          variant={dose.isFed ? "default" : "outline"}
                          className={`h-9 w-9 p-0 ${dose.isFed ? 'bg-orange-500 hover:bg-orange-600' : ''}`}
                        />
                        <IconButtonWithTooltip
                          onClick={() => handleActionWithSort(day.id, () => onRemoveDose(day.id, dose.id))}
                          icon={<Trash2 className="h-4 w-4" />}
                          tooltip={t('removeDose')}
                          size="sm"
                          variant="outline"
                          disabled={day.isTemplate && day.doses.length === 1}
                          className="h-9 w-9 p-0 text-destructive hover:bg-destructive hover:text-destructive-foreground disabled:border-muted"
                        />
                      </div>
                    </div>
                  </div>
                );
              })}

              {/* Add dose button */}
              {day.doses.length < MAX_DOSES_PER_DAY && (
                <Button
                  onClick={() => onAddDose(day.id)}
                  size="sm"
                  variant="outline"
                  className="w-full mt-2"
                >
                  <Plus className="h-4 w-4 mr-2" />
                  {t('addDose')}
                </Button>
              )}
            </CardContent>
          )}
          </Card>
        )})}

      {/* Add day button */}
      {canAddDay && (
        <Button
          onClick={() => onAddDay()}
          variant="outline"
          className="w-full"
        >
          <Plus className="h-4 w-4 mr-2" />
          {t('addDay')}
        </Button>
      )}
    </div>
  );
};

export default DaySchedule;
