"use client";

import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import {
  Box,
  Typography,
  FormControl,
  InputLabel,
  Select,
  MenuItem,
  Card,
  CardContent,
  Stack,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  CircularProgress,
  Chip
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs';
import { fetchTruckScheduleDashboardClient, type TruckScheduleDashboardItem } from '@/app/api/do/client';
import { formatDepartureTime, arrayToDayjs } from '@/app/utils/formatUtil';

// Track completed items for hiding after 2 refresh cycles
interface CompletedTracker {
  key: string;
  refreshCount: number;
}

// Data stored per date for instant switching
interface DateData {
  today: TruckScheduleDashboardItem[];
  tomorrow: TruckScheduleDashboardItem[];
  dayAfterTomorrow: TruckScheduleDashboardItem[];
}

// Storage structure for persisting completed tracker state
interface PersistedTrackerState {
  completedTracker: {
    [dateOption: string]: { [key: string]: CompletedTracker };
  };
  refreshCount: {
    [dateOption: string]: number;
  };
}

const STORAGE_KEY = 'truckScheduleCompletedTracker';

const TruckScheduleDashboard: React.FC = () => {
  const { t } = useTranslation("dashboard");
  const [selectedStore, setSelectedStore] = useState<string>("");
  const [selectedDate, setSelectedDate] = useState<string>("today");
  // Store data for all three dates for instant switching
  const [allData, setAllData] = useState<DateData>({ today: [], tomorrow: [], dayAfterTomorrow: [] });
  const [loading, setLoading] = useState<boolean>(true);
  // Initialize as null to avoid SSR/client hydration mismatch
  const [currentTime, setCurrentTime] = useState<dayjs.Dayjs | null>(null);
  const [isClient, setIsClient] = useState<boolean>(false);
  // Track when data was last refreshed (not current time)
  const [lastDataRefreshTime, setLastDataRefreshTime] = useState<dayjs.Dayjs | null>(null);
  // Track completed items per date
  const completedTrackerRef = useRef<Map<string, Map<string, CompletedTracker>>>(new Map([
    ['today', new Map()],
    ['tomorrow', new Map()],
    ['dayAfterTomorrow', new Map()]
  ]));
  const refreshCountRef = useRef<Map<string, number>>(new Map([
    ['today', 0],
    ['tomorrow', 0],
    ['dayAfterTomorrow', 0]
  ]));
  
  // Save completed tracker state to sessionStorage
  const saveCompletedTrackerToStorage = useCallback(() => {
    if (typeof window === 'undefined') return;
    
    try {
      const completedTrackerObj: { [dateOption: string]: { [key: string]: CompletedTracker } } = {};
      const refreshCountObj: { [dateOption: string]: number } = {};
      
      // Convert Maps to plain objects
      completedTrackerRef.current.forEach((tracker, dateOption) => {
        completedTrackerObj[dateOption] = Object.fromEntries(tracker);
      });
      
      refreshCountRef.current.forEach((count, dateOption) => {
        refreshCountObj[dateOption] = count;
      });
      
      const state: PersistedTrackerState = {
        completedTracker: completedTrackerObj,
        refreshCount: refreshCountObj
      };
      
      sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));
    } catch (error) {
      console.warn('Failed to save completed tracker to sessionStorage:', error);
    }
  }, []);

  // Load completed tracker state from sessionStorage
  const loadCompletedTrackerFromStorage = useCallback((): boolean => {
    if (typeof window === 'undefined') return false;
    
    try {
      const saved = sessionStorage.getItem(STORAGE_KEY);
      if (!saved) return false;
      
      const state: PersistedTrackerState = JSON.parse(saved);
      
      // Reconstruct Maps from plain objects
      const completedTrackerMap = new Map<string, Map<string, CompletedTracker>>();
      const refreshCountMap = new Map<string, number>();
      
      Object.entries(state.completedTracker).forEach(([dateOption, trackerObj]) => {
        completedTrackerMap.set(dateOption, new Map(Object.entries(trackerObj)));
      });
      
      Object.entries(state.refreshCount).forEach(([dateOption, count]) => {
        refreshCountMap.set(dateOption, count);
      });
      
      completedTrackerRef.current = completedTrackerMap;
      refreshCountRef.current = refreshCountMap;
      
      return true;
    } catch (error) {
      console.warn('Failed to load completed tracker from sessionStorage:', error);
      return false;
    }
  }, []);

  // Get date label for display (e.g., "2026-01-17")
  const getDateLabel = (offset: number): string => {
    return dayjs().add(offset, 'day').format('YYYY-MM-DD');
  };

  // Get day offset based on date option
  const getDateOffset = (dateOption: string): number => {
    if (dateOption === "today") return 0;
    if (dateOption === "tomorrow") return 1;
    if (dateOption === "dayAfterTomorrow") return 2;
    return 0;
  };

  // Convert date option to YYYY-MM-DD format for API
  const getDateParam = (dateOption: string): string => {
    const offset = getDateOffset(dateOption);
    return dayjs().add(offset, 'day').format('YYYY-MM-DD');
  };
  
  // Set client flag and time on mount, load persisted state
  useEffect(() => {
    setIsClient(true);
    setCurrentTime(dayjs());
    // Load persisted completed tracker state from sessionStorage
    loadCompletedTrackerFromStorage();
  }, [loadCompletedTrackerFromStorage]);

  // Format time from array or string to HH:mm
  const formatTime = (timeData: string | number[] | null): string => {
    if (!timeData) return '-';
    
    if (Array.isArray(timeData)) {
      if (timeData.length >= 2) {
        const hour = timeData[0] || 0;
        const minute = timeData[1] || 0;
        return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
      }
      return '-';
    }
    
    if (typeof timeData === 'string') {
      const parts = timeData.split(':');
      if (parts.length >= 2) {
        const hour = parseInt(parts[0], 10);
        const minute = parseInt(parts[1], 10);
        return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
      }
    }
    
    return '-';
  };

  // Format datetime from array or string
  const formatDateTime = (dateTimeData: string | number[] | null): string => {
    if (!dateTimeData) return '-';
    
    if (Array.isArray(dateTimeData)) {
      return arrayToDayjs(dateTimeData, true).format('HH:mm');
    }
    
    const parsed = dayjs(dateTimeData);
    if (parsed.isValid()) {
      return parsed.format('HH:mm');
    }
    
    return '-';
  };

  // Calculate time remaining for truck departure
  const calculateTimeRemaining = useCallback((item: TruckScheduleDashboardItem, dateOption: string): string => {
    // If all tickets are completed, return the difference between ETD and last ticket end time
    if (item.numberOfPickTickets > 0 && item.numberOfTicketsCompleted >= item.numberOfPickTickets) {
      const lastTicketEndTime = item.lastTicketEndTime;
      const departureTime = item.truckDepartureTime;
      
      if (!lastTicketEndTime || !departureTime) return '-';
      
      // Parse last ticket end time
      let lastEndDayjs: dayjs.Dayjs;
      if (Array.isArray(lastTicketEndTime)) {
        lastEndDayjs = arrayToDayjs(lastTicketEndTime, true);
      } else if (typeof lastTicketEndTime === 'string') {
        lastEndDayjs = dayjs(lastTicketEndTime);
        if (!lastEndDayjs.isValid()) return '-';
      } else {
        return '-';
      }
      
      // Parse departure time
      const dateOffset = getDateOffset(dateOption);
      const baseDate = dayjs().add(dateOffset, 'day');
      let departureDayjs: dayjs.Dayjs;
      
      if (Array.isArray(departureTime)) {
        if (departureTime.length < 2) return '-';
        const hour = departureTime[0] || 0;
        const minute = departureTime[1] || 0;
        departureDayjs = baseDate.hour(hour).minute(minute).second(0);
      } else if (typeof departureTime === 'string') {
        const parts = departureTime.split(':');
        if (parts.length < 2) return '-';
        const hour = parseInt(parts[0], 10);
        const minute = parseInt(parts[1], 10);
        departureDayjs = baseDate.hour(hour).minute(minute).second(0);
      } else {
        return '-';
      }
      
      // Calculate difference: ETD - lastTicketEndTime
      const diffMinutes = departureDayjs.diff(lastEndDayjs, 'minute');
      
      if (diffMinutes < 0) {
        // ETD is before last ticket end (negative difference)
        const absDiff = Math.abs(diffMinutes);
        const hours = Math.floor(absDiff / 60);
        const minutes = absDiff % 60;
        return `-${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
      } else {
        // ETD is after last ticket end (positive difference)
        const hours = Math.floor(diffMinutes / 60);
        const minutes = diffMinutes % 60;
        return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
      }
    }
    
    const departureTime = item.truckDepartureTime;
    if (!departureTime || !currentTime) return '-';
    
    const now = currentTime;
    let departureHour: number;
    let departureMinute: number;
    
    if (Array.isArray(departureTime)) {
      if (departureTime.length < 2) return '-';
      departureHour = departureTime[0] || 0;
      departureMinute = departureTime[1] || 0;
    } else if (typeof departureTime === 'string') {
      const parts = departureTime.split(':');
      if (parts.length < 2) return '-';
      departureHour = parseInt(parts[0], 10);
      departureMinute = parseInt(parts[1], 10);
    } else {
      return '-';
    }
    
    // Create departure datetime for the selected date (today, tomorrow, or day after tomorrow)
    const dateOffset = getDateOffset(dateOption);
    const departure = now.clone().add(dateOffset, 'day').hour(departureHour).minute(departureMinute).second(0);
    const diffMinutes = departure.diff(now, 'minute');
    
    if (diffMinutes < 0) {
      // Past departure time
      const absDiff = Math.abs(diffMinutes);
      const hours = Math.floor(absDiff / 60);
      const minutes = absDiff % 60;
      return `-${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
    } else {
      const hours = Math.floor(diffMinutes / 60);
      const minutes = diffMinutes % 60;
      return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
    }
  }, [currentTime]);

  // Generate unique key for tracking completed items
  const getItemKey = (item: TruckScheduleDashboardItem): string => {
    return `${item.storeId}-${item.truckLanceCode}-${item.truckDepartureTime}`;
  };

  // Process data for a specific date option with completed tracker logic
  const processDataForDate = useCallback((result: TruckScheduleDashboardItem[], dateOption: string): TruckScheduleDashboardItem[] => {
    const tracker = completedTrackerRef.current.get(dateOption) || new Map();
    const currentRefresh = (refreshCountRef.current.get(dateOption) || 0) + 1;
    refreshCountRef.current.set(dateOption, currentRefresh);
    
    result.forEach(item => {
      const key = getItemKey(item);
      // If all tickets are completed, track it
      if (item.numberOfPickTickets > 0 && item.numberOfTicketsCompleted >= item.numberOfPickTickets) {
        const existing = tracker.get(key);
        if (!existing) {
          tracker.set(key, { key, refreshCount: currentRefresh });
        }
      } else {
        // Remove from tracker if no longer completed
        tracker.delete(key);
      }
    });
    
    completedTrackerRef.current.set(dateOption, tracker);
    
    // Save to sessionStorage after updating tracker
    saveCompletedTrackerToStorage();
    
    // Filter out items that have been completed for 2+ refresh cycles
    return result.filter(item => {
      const key = getItemKey(item);
      const itemTracker = tracker.get(key);
      if (itemTracker) {
        // Hide if completed for 2 or more refresh cycles
        if (currentRefresh - itemTracker.refreshCount >= 2) {
          return false;
        }
      }
      return true;
    });
  }, [saveCompletedTrackerToStorage]);

  // Load data for all three dates in parallel for instant switching
  const loadData = useCallback(async (isInitialLoad: boolean = false) => {
    // Only show loading spinner on initial load, not during refresh
    if (isInitialLoad) {
      setLoading(true);
    }
    try {
      const dateOptions = ['today', 'tomorrow', 'dayAfterTomorrow'] as const;
      const dateParams = dateOptions.map(opt => getDateParam(opt));
      
      // Fetch all three dates in parallel
      const [todayResult, tomorrowResult, dayAfterResult] = await Promise.all([
        fetchTruckScheduleDashboardClient(dateParams[0]),
        fetchTruckScheduleDashboardClient(dateParams[1]),
        fetchTruckScheduleDashboardClient(dateParams[2])
      ]);
      
      // Process each date's data with completed tracker logic
      setAllData({
        today: processDataForDate(todayResult, 'today'),
        tomorrow: processDataForDate(tomorrowResult, 'tomorrow'),
        dayAfterTomorrow: processDataForDate(dayAfterResult, 'dayAfterTomorrow')
      });
      
      // Update last data refresh time only when data is successfully loaded
      setLastDataRefreshTime(dayjs());
    } catch (error) {
      console.error('Error fetching truck schedule dashboard:', error);
    } finally {
      if (isInitialLoad) {
        setLoading(false);
      }
    }
  }, [processDataForDate]);

  // Initial load and auto-refresh every 5 minutes
  useEffect(() => {
    loadData(true); // Initial load - show spinner
    
    const refreshInterval = setInterval(() => {
      loadData(false); // Refresh - don't show spinner, keep existing data visible
    }, 5 * 60 * 1000); // 5 minutes
    
    return () => clearInterval(refreshInterval);
  }, [loadData]);

  // Update current time every 1 minute for time remaining calculation
  useEffect(() => {
    if (!isClient) return;
    
    const timeInterval = setInterval(() => {
      setCurrentTime(dayjs());
    }, 60 * 1000); // 1 minute
    
    return () => clearInterval(timeInterval);
  }, [isClient]);

  // Get data for selected date, then filter by store - both filters are instant
  const filteredData = useMemo(() => {
    // First get the data for the selected date
    const dateData = allData[selectedDate as keyof DateData] || [];
    // Then filter by store if selected
    if (!selectedStore) return dateData;
    return dateData.filter(item => item.storeId === selectedStore);
  }, [allData, selectedDate, selectedStore]);

  // Get chip color based on time remaining
  const getTimeChipColor = (departureTime: string | number[] | null, dateOption: string): "success" | "warning" | "error" | "default" => {
    if (!departureTime || !currentTime) return "default";
    
    const now = currentTime;
    let departureHour: number;
    let departureMinute: number;
    
    if (Array.isArray(departureTime)) {
      if (departureTime.length < 2) return "default";
      departureHour = departureTime[0] || 0;
      departureMinute = departureTime[1] || 0;
    } else if (typeof departureTime === 'string') {
      const parts = departureTime.split(':');
      if (parts.length < 2) return "default";
      departureHour = parseInt(parts[0], 10);
      departureMinute = parseInt(parts[1], 10);
    } else {
      return "default";
    }
    
    // Create departure datetime for the selected date (today, tomorrow, or day after tomorrow)
    const dateOffset = getDateOffset(dateOption);
    const departure = now.clone().add(dateOffset, 'day').hour(departureHour).minute(departureMinute).second(0);
    const diffMinutes = departure.diff(now, 'minute');
    
    if (diffMinutes < 0) return "error"; // Past due
    if (diffMinutes <= 30) return "warning"; // Within 30 minutes
    return "success"; // More than 30 minutes
  };

  return (
    <Card sx={{ mb: 2 }}>
      <CardContent>
        {/* Filter */}
        <Stack direction="row" spacing={2} sx={{ mb: 3 }}>
          <FormControl sx={{ minWidth: 150 }} size="small">
            <InputLabel id="store-select-label" shrink={true}>
              {t("Store ID")}
            </InputLabel>
            <Select
              labelId="store-select-label"
              id="store-select"
              value={selectedStore}
              label={t("Store ID")}
              onChange={(e) => setSelectedStore(e.target.value)}
              displayEmpty
            >
              <MenuItem value="">{t("All Stores")}</MenuItem>
              <MenuItem value="2/F">2/F</MenuItem>
              <MenuItem value="4/F">4/F</MenuItem>
            </Select>
          </FormControl>

          <FormControl sx={{ minWidth: 200 }} size="small">
            <InputLabel id="date-select-label" shrink={true}>
              {t("Select Date")}
            </InputLabel>
            <Select
              labelId="date-select-label"
              id="date-select"
              value={selectedDate}
              label={t("Select Date")}
              onChange={(e) => setSelectedDate(e.target.value)}
            >
              <MenuItem value="today">{t("Today")} ({getDateLabel(0)})</MenuItem>
              <MenuItem value="tomorrow">{t("Tomorrow")} ({getDateLabel(1)})</MenuItem>
              <MenuItem value="dayAfterTomorrow">{t("Day After Tomorrow")} ({getDateLabel(2)})</MenuItem>
            </Select>
          </FormControl>
          
          <Typography variant="body2" sx={{ alignSelf: 'center', color: 'text.secondary' }}>
            {t("Auto-refresh every 5 minutes")} | {t("Last updated")}: {isClient && lastDataRefreshTime ? lastDataRefreshTime.format('HH:mm:ss') : '--:--:--'}
          </Typography>
        </Stack>

        {/* Table */}
        <Box sx={{ mt: 2 }}>
          {loading ? (
            <Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
              <CircularProgress />
            </Box>
          ) : (
            <TableContainer component={Paper}>
              <Table size="small" sx={{ minWidth: 1200 }}>
                <TableHead>
                  <TableRow sx={{ backgroundColor: 'grey.100' }}>
                    <TableCell sx={{ fontWeight: 600 }}>{t("Store ID")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }}>{t("Truck Schedule")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }}>{t("Time Remaining")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }} align="center">{t("No. of Shops")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }} align="center">{t("Tickets Released")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }} align="center">{t("Tickets Completed")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }} align="center">{t("Total Items")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }}>{t("First Ticket Start")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }}>{t("Last Ticket End")}</TableCell>
                    <TableCell sx={{ fontWeight: 600 }} align="center">{t("Pick Time (min)")}</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {filteredData.length === 0 ? (
                    <TableRow>
                      <TableCell colSpan={10} align="center">
                        <Typography variant="body2" color="text.secondary">
                          {t("No truck schedules available")} ({getDateParam(selectedDate)})
                        </Typography>
                      </TableCell>
                    </TableRow>
                  ) : (
                    filteredData.map((row, index) => {
                      const timeRemaining = calculateTimeRemaining(row, selectedDate);
                      const chipColor = getTimeChipColor(row.truckDepartureTime, selectedDate);
                      
                      return (
                        <TableRow 
                          key={`${row.storeId}-${row.truckLanceCode}-${index}`}
                          sx={{ 
                            '&:hover': { backgroundColor: 'grey.50' },
                            backgroundColor: row.numberOfPickTickets > 0 && row.numberOfTicketsCompleted >= row.numberOfPickTickets 
                              ? 'rgba(76, 175, 80, 0.15)' 
                              : 'inherit'
                          }}
                        >
                          <TableCell>
                            <Chip 
                              label={row.storeId || '-'} 
                              size="small" 
                              color={row.storeId === '2/F' ? 'primary' : 'secondary'}
                            />
                          </TableCell>
                          <TableCell>
                            <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
                              <Typography variant="body2" sx={{ fontWeight: 500 }}>
                                {row.truckLanceCode || '-'}
                              </Typography>
                              <Typography variant="caption" color="text.secondary">
                                ETD: {formatTime(row.truckDepartureTime)}
                              </Typography>
                            </Box>
                          </TableCell>
                          <TableCell>
                            <Chip 
                              label={timeRemaining}
                              size="small"
                              color={chipColor}
                              sx={{ fontWeight: 600 }}
                            />
                          </TableCell>
                          <TableCell align="center">
                            <Typography variant="body2">
                              {row.numberOfShopsToServe} [{row.numberOfPickTickets}]
                            </Typography>
                          </TableCell>
                          <TableCell align="center">
                            <Chip 
                              label={row.numberOfTicketsReleased}
                              size="small"
                              color={row.numberOfTicketsReleased > 0 ? 'info' : 'default'}
                            />
                          </TableCell>
                          <TableCell align="center">
                            <Chip 
                              label={row.numberOfTicketsCompleted}
                              size="small"
                              color={row.numberOfTicketsCompleted > 0 ? 'success' : 'default'}
                            />
                          </TableCell>
                          <TableCell align="center">
                            <Typography variant="body2" sx={{ fontWeight: 500 }}>
                              {row.totalItemsToPick}
                            </Typography>
                          </TableCell>
                          <TableCell>
                            {formatDateTime(row.firstTicketStartTime)}
                          </TableCell>
                          <TableCell>
                            {formatDateTime(row.lastTicketEndTime)}
                          </TableCell>
                          <TableCell align="center">
                            <Typography 
                              variant="body2" 
                              sx={{ 
                                fontWeight: 500,
                                color: row.pickTimeTakenMinutes !== null ? 'text.primary' : 'text.secondary'
                              }}
                            >
                              {row.pickTimeTakenMinutes !== null ? row.pickTimeTakenMinutes : '-'}
                            </Typography>
                          </TableCell>
                        </TableRow>
                      );
                    })
                  )}
                </TableBody>
              </Table>
            </TableContainer>
          )}
        </Box>
      </CardContent>
    </Card>
  );
};

export default TruckScheduleDashboard;
