import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';

import Paper from '@material-hu/mui/Paper';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';
import { useTheme } from '@material-hu/mui/styles';
import { IconChevronLeft, IconChevronRight } from '@material-hu/icons/tabler';
import IconButton from '@material-hu/mui/IconButton';

import Checkbox from '@material-hu/components/design-system/Checkbox/Checkbox';
import Box from '@material-hu/mui/Box';
import Table from '@material-hu/components/design-system/Table';
import TableCell from '@material-hu/components/design-system/Table/components/TableCell';
import TableContainer from '@material-hu/components/design-system/Table/components/TableContainer';
import TableHead from '@material-hu/components/design-system/Table/components/TableHead';
import TableRow from '@material-hu/components/design-system/Table/components/TableRow';

import { type ShiftCalendarUser } from 'src/types/shifts';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { useLayoutContext } from 'src/contexts/LayoutContext';

import { WeekMonthPeriod } from '@material-hu/components/composed-components/WeekMonthSelector/types';

import { TABLE_HEADERS_IDS } from '../../constants';
import { useShiftsSelectionActions } from '../../contexts/ShiftsSelectionContext';

import { STICKY_COLUMN_SX } from '../ShiftsTable/constants';
import { getColumnCheckboxState, getShiftsForDate } from '../ShiftsTable/utils';
import Skeleton from '@material-hu/components/design-system/Skeleton';

const SELECTION_COL_WIDTH = 50;

type Props = {
  isLoading: boolean;
  registers: ShiftCalendarUser[];
  days: { key: string; label: string }[];
  selectionActive: boolean;
  userCount: string;
  scrollRef: (element: HTMLElement | null) => void;
  showScrollButtons?: boolean;
  onScroll?: (amount: number) => void;
};

const StickyHeader = forwardRef<HTMLDivElement, Props>(
  (
    {
      isLoading,
      registers,
      days,
      selectionActive,
      userCount,
      scrollRef,
      showScrollButtons,
      onScroll,
    },
    ref,
  ) => {
    const { taskFocus } = useLayoutContext();
    const { palette } = useTheme();
    const containerElRef = useRef<HTMLElement | null>(null);
    const [canScrollLeft, setCanScrollLeft] = useState(false);
    const [canScrollRight, setCanScrollRight] = useState(false);

    const checkScrollability = useCallback((el: HTMLElement) => {
      const { scrollLeft, scrollWidth, clientWidth } = el;
      setCanScrollLeft(scrollLeft > 0);
      setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 1);
    }, []);

    const combinedScrollRef = useCallback(
      (element: HTMLElement | null) => {
        containerElRef.current = element;
        if (scrollRef) scrollRef(element);
        if (element) checkScrollability(element);
      },
      [scrollRef, checkScrollability],
    );

    // Re-check when days change (different number of columns)
    useEffect(() => {
      if (containerElRef.current) checkScrollability(containerElRef.current);
    }, [days, checkScrollability]);

    useEffect(() => {
      const el = containerElRef.current;
      if (!el) return;
      const handleScroll = () => checkScrollability(el);
      el.addEventListener('scroll', handleScroll);
      return () => el.removeEventListener('scroll', handleScroll);
    }, [checkScrollability]);

    const containerRef = combinedScrollRef;
    const { t } = useLokaliseTranslation();
    const [hoveredColumn, setHoveredColumn] = useState<string | null>(null);
    const [isCollaboratorRowHovered, setIsCollaboratorRowHovered] =
      useState(false);
    const [skipTransition, setSkipTransition] = useState(false);

    useEffect(() => {
      setSkipTransition(true);
      const id = setTimeout(() => setSkipTransition(false), 250);
      return () => clearTimeout(id);
    }, [selectionActive]);

    const {
      isAdvancedMode,
      selectedDates,
      selectedCells,
      excludeCells,
      excludeShifts,
      handleDateSelection,
      allRowsSelected,
      toggleSelectAll,
      viewMode,
    } = useShiftsSelectionActions();

    const isMonthlyView = viewMode === WeekMonthPeriod.MONTHLY;

    const handleSelectAll = (event: React.MouseEvent<HTMLButtonElement>) => {
      event.stopPropagation();
      toggleSelectAll(days, registers);
    };

    const allChecked =
      (allRowsSelected || selectedDates.size === days.length) &&
      !excludeCells.length &&
      !excludeShifts.size;
    const allIndeterminate =
      !allChecked &&
      ((selectedDates.size > 0 && selectedDates.size < days.length) ||
        selectedCells.length > 0 ||
        excludeCells.length > 0 ||
        excludeShifts.size > 0);

    const scrollButtonSx = {
      position: 'absolute' as const,
      top: '50%',
      transform: 'translateY(-50%)',
      zIndex: 20,
      width: 32,
      height: 32,
      minWidth: 32,
      backgroundColor: palette.new.background.layout.default,
      border: `1px solid ${palette.new.border.neutral.default}`,
      boxShadow: '0px 2px 8px rgba(0,0,0,0.15)',
      borderRadius: '50%',
      '&:hover': {
        backgroundColor: palette.new.background.layout.default,
        boxShadow: '0px 4px 12px rgba(0,0,0,0.2)',
      },
    };

    return (
      <Box sx={{ position: 'relative' }}>
        <TableContainer
          component={Paper}
          containerRef={containerRef}
          sx={{
            borderRadius: 0,
            boxShadow: 'none',
            backgroundColor: ({ palette }) =>
              palette.new.background.elements.grey,
            overflowY: 'hidden',
            scrollbarWidth: 'none',
            '&::-webkit-scrollbar': {
              display: 'none',
            },
          }}
        >
          <Table
            id={TABLE_HEADERS_IDS.tableHeader}
            sx={{ tableLayout: 'fixed', minWidth: 1200 }}
            aria-label={t('shifts:shifts_table_header')}
            aria-colcount={selectionActive ? days.length + 2 : days.length + 1}
            stickyHeader
          >
            <TableHead>
              <TableRow>
                {selectionActive && (
                  <TableCell
                    align="center"
                    id={TABLE_HEADERS_IDS.selectionHeader}
                    sx={{
                      // Beat the MuiTableHead styleOverride that paints cells with
                      // a translucent tint (it leaks scrolled columns under the
                      // sticky column). Needs MuiTableCell-root specificity to win.
                      '&.MuiTableCell-root': {
                        backgroundColor: ({ palette }) =>
                          palette.new.background.elements.grey,
                      },
                      position: 'sticky',
                      left: 0,
                      zIndex: 4,
                      width: SELECTION_COL_WIDTH,
                    }}
                    headerCell
                  >
                    <Checkbox
                      checked={allChecked}
                      indeterminate={allIndeterminate}
                      onClick={handleSelectAll}
                    />
                  </TableCell>
                )}

                <TableCell
                  align="left"
                  id={TABLE_HEADERS_IDS.collaboratorHeader}
                  sx={{
                    ...STICKY_COLUMN_SX,
                    // Beat the MuiTableHead styleOverride that paints cells with
                    // a translucent tint (it leaks scrolled columns under the
                    // sticky column). Needs MuiTableCell-root specificity to win.
                    '&.MuiTableCell-root': {
                      backgroundColor: ({ palette }) =>
                        palette.new.background.elements.grey,
                    },
                    zIndex: 3, // Higher than the body and other header cells
                    ...(selectionActive && {
                      left: SELECTION_COL_WIDTH,
                    }),
                    width: STICKY_COLUMN_SX.width - 1,
                    padding: 0,
                  }}
                  headerCell
                >
                  <Stack
                    onMouseEnter={() => setIsCollaboratorRowHovered(true)}
                    onMouseLeave={() => setIsCollaboratorRowHovered(false)}
                    sx={{
                      alignItems: 'center',
                      flexDirection: 'row',
                      gap: 1,
                      overflow: 'visible',
                      position: 'relative',
                      width: '100%',
                      minHeight: '100%',
                      padding: 3,
                    }}
                  >
                    <Box
                      sx={{
                        display: 'flex',
                        alignItems: 'center',
                        gap: 1,
                        position: 'relative',
                        width: '100%',
                      }}
                    >
                      {!selectionActive && isCollaboratorRowHovered && (
                        <Box
                          sx={{
                            position: 'absolute',
                            left: 0,
                            zIndex: 1,
                            opacity: 0,
                            animation: 'fadeIn 0.2s ease-in-out forwards',
                            '@keyframes fadeIn': {
                              to: { opacity: 1 },
                            },
                          }}
                        >
                          <Checkbox
                            checked={allChecked}
                            indeterminate={allIndeterminate}
                            onClick={handleSelectAll}
                          />
                        </Box>
                      )}
                      {isLoading ? (
                        <Skeleton
                          variant="rounded"
                          sx={{ width: '100%', height: 33 }}
                        />
                      ) : (
                        <Typography
                          variant="globalS"
                          sx={{
                            fontWeight: 'fontWeightSemiBold',
                            transform: `translateX(${!selectionActive && isCollaboratorRowHovered ? 40 : 0}px)`,
                            transition:
                              !selectionActive &&
                              isCollaboratorRowHovered &&
                              !skipTransition
                                ? 'transform 0.2s ease-in-out'
                                : 'none',
                          }}
                        >
                          {t('general:collaborator')} ({userCount})
                        </Typography>
                      )}
                    </Box>
                  </Stack>
                </TableCell>

                {days.map(d => {
                  const allShiftIdsInDate = getShiftsForDate(d.key, registers);
                  const {
                    checked: colChecked,
                    indeterminate: colIndeterminate,
                  } = getColumnCheckboxState({
                    date: d.key,
                    selectedDates,
                    selectedCells,
                    excludeCells,
                    excludeShifts,
                    dateShifts: allShiftIdsInDate,
                  });

                  return (
                    <TableCell
                      key={d.key}
                      align="center"
                      id={TABLE_HEADERS_IDS.dateHeader(d.key)}
                      onClick={() => {
                        handleDateSelection(
                          d.key,
                          colChecked,
                          colIndeterminate,
                          days.length,
                          allShiftIdsInDate,
                        );
                      }}
                      onMouseEnter={() => setHoveredColumn(d.key)}
                      onMouseLeave={() => setHoveredColumn(null)}
                      sx={{
                        // Beat the MuiTableHead styleOverride that paints cells
                        // with a translucent tint (it leaks scrolled columns
                        // under the sticky column). Needs MuiTableCell-root
                        // specificity to win.
                        '&.MuiTableCell-root': {
                          backgroundColor: ({ palette }) =>
                            colChecked
                              ? palette.new.background.layout.brand
                              : palette.new.background.elements.grey,
                        },
                        textTransform: 'capitalize',
                        cursor: 'pointer',
                        ...(isMonthlyView && { width: 67, px: 0 }),
                      }}
                      headerCell
                    >
                      {isMonthlyView ? (
                        <Stack
                          sx={{
                            alignItems: 'center',
                            justifyContent: 'center',
                          }}
                        >
                          {/* Decorative only: selection is handled by the cell
                              onClick. Hidden from a11y tree and tab order. */}
                          <Box
                            aria-hidden
                            sx={{ mb: 0.5 }}
                          >
                            <Checkbox
                              checked={colChecked}
                              indeterminate={colIndeterminate}
                              sx={{
                                p: 0,
                                opacity:
                                  colChecked ||
                                  isAdvancedMode ||
                                  hoveredColumn === d.key
                                    ? 1
                                    : 0,
                                pointerEvents: 'none',
                                '& input': { display: 'none' },
                              }}
                            />
                          </Box>
                          <Typography
                            variant="globalS"
                            sx={{
                              fontWeight: 'fontWeightSemiBold',
                              lineHeight: 1.2,
                            }}
                          >
                            {d.label.charAt(0).toUpperCase()}
                          </Typography>
                          <Typography
                            variant="globalS"
                            sx={{ lineHeight: 1.2 }}
                          >
                            {d.key.slice(-2)}
                          </Typography>
                        </Stack>
                      ) : (
                        <Stack
                          sx={{
                            flexDirection: 'row',
                            gap: 1,
                            alignItems: 'center',
                            justifyContent: 'center',
                          }}
                        >
                          {/* Decorative only: selection is handled by the cell
                              onClick. Hidden from a11y tree and tab order. */}
                          <Box
                            aria-hidden
                            sx={{ display: 'flex' }}
                          >
                            <Checkbox
                              checked={colChecked}
                              indeterminate={colIndeterminate}
                              sx={{
                                opacity:
                                  colChecked ||
                                  isAdvancedMode ||
                                  hoveredColumn === d.key
                                    ? 1
                                    : 0,
                                pointerEvents: 'none',
                                '& input': { display: 'none' },
                              }}
                            />
                          </Box>
                          <Typography
                            variant="globalS"
                            sx={{
                              fontWeight: 'fontWeightSemiBold',
                              whiteSpace: 'nowrap',
                            }}
                          >
                            {d.label}
                          </Typography>
                        </Stack>
                      )}
                    </TableCell>
                  );
                })}
              </TableRow>
            </TableHead>
          </Table>
        </TableContainer>
        {onScroll && canScrollLeft && (
          <IconButton
            onClick={() => onScroll(-1)}
            sx={{
              ...scrollButtonSx,
              left:
                (selectionActive ? SELECTION_COL_WIDTH : 0) +
                (taskFocus
                  ? STICKY_COLUMN_SX.width + 8
                  : STICKY_COLUMN_SX.width - 16),
            }}
          >
            <IconChevronLeft size={16} />
          </IconButton>
        )}
        {onScroll && canScrollRight && (
          <IconButton
            onClick={() => onScroll(1)}
            sx={{ ...scrollButtonSx, right: taskFocus ? 8 : -16 }}
          >
            <IconChevronRight size={16} />
          </IconButton>
        )}
      </Box>
    );
  },
);

StickyHeader.displayName = 'StickyHeader';

export default StickyHeader;
