import { type FC, type RefObject, useRef, useState } from 'react';
import { useFormContext } from 'react-hook-form';

import { format } from 'date-fns';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';
import { DatePicker } from '@material-hu/mui/x-date-pickers/DatePicker';
import { DesktopDateTimePicker } from '@material-hu/mui/x-date-pickers/DesktopDateTimePicker';
import { DesktopTimePicker } from '@material-hu/mui/x-date-pickers/DesktopTimePicker';

import HuTooltip from '@material-hu/components/design-system/Tooltip';

import { useAuth } from 'src/contexts/JWTContext';
import {
  type SectionComponent,
  type TextStyles,
} from 'src/pages/dashboard/serviceManagement/types';
import { getCurrentLocale } from 'src/utils/locale';

import { usePdfCompletion } from '../../contexts/PdfFormCompletionProvider';
import {
  DATE_DD_MM_YYYY,
  DATE_MM_DD_YYYY,
  DATE_MM_YYYY,
  DATETIME_DD_MM_YYYY_HH_MM_SS,
  type DatePattern,
  TIME_HH_MM,
  TYPOGRAPHY_OVERFLOW_SX_PROPS,
} from '../utils/constants';
import {
  getFieldContainerSxProps,
  getViewsForPattern,
  isValidDateOrTimeValue,
} from '../utils/utils';

import useFieldErrorMessages from './useFieldErrorMessages';
import useFocusField from './useFocusField';

type Props = {
  field: SectionComponent;
  dimensions: {
    width: number;
    height: number;
  };
  textStyles: TextStyles;
};

// We need to use hardcoded colors because the theme colors are not applied correctly to the date picker. Not sure why.
const primaryHugoColor = '#496BE3';
const scrollbarWidth = '4px';
const bgWhite = '#fff';
const datePickerFontSize = '14px';
const datePickerFontWeight = 600;

const DateField: FC<Props> = ({ field, textStyles, dimensions }) => {
  const {
    nameId: name,
    content: { title, required },
    validations,
  } = field;

  const pattern = validations?.pattern as DatePattern;

  const { user } = useAuth();
  const { watch, setValue } = useFormContext();
  const { showErrors } = usePdfCompletion();
  const theme = useTheme();
  const answer = watch(name);
  const { hasErrors, getTooltipProps } = useFieldErrorMessages({
    showErrors,
    field,
    answer,
  });
  const { isFocused, handleFocus, removeFocus, inputRef } = useFocusField();

  const [isTimePickerOpen, setIsTimePickerOpen] = useState(false);
  const isOpeningRef = useRef(false);

  const dimensionSxProps = {
    width: `${dimensions.width}px`,
    height: `${dimensions.height}px`,
  };

  const hasAnswer = isValidDateOrTimeValue(answer);

  const textFieldSxProps = {
    ...textStyles,
    lineHeight: '1 !important',
    borderRadius: '2px !important',
    p: '0 !important',
    width: `${dimensions.width}px !important`,
    height: `${dimensions.height}px !important`,
    '& .MuiInputBase-root': {
      borderRadius: '2px !important',
      p: '0 !important',
      width: `${dimensions.width}px !important`,
      height: `${dimensions.height}px !important`,
    },
    '& .MuiInputAdornment-root': {
      display: 'none !important',
    },
    '& input': {
      borderRadius: '2px !important',
      p: '2px !important',
      ...textStyles,
      width: `${dimensions.width}px !important`,
      height: `${dimensions.height}px !important`,
    },
  };

  // Input (focused)
  if (isFocused) {
    switch (pattern) {
      case DATE_DD_MM_YYYY:
      case DATE_MM_DD_YYYY:
      case DATE_MM_YYYY:
        return (
          <DatePicker
            onChange={value => {
              setValue(name, value);
              removeFocus();
            }}
            onOpen={() => {
              setIsTimePickerOpen(true);
              isOpeningRef.current = false;
            }}
            open
            onClose={() => {
              setIsTimePickerOpen(false);
              removeFocus();
            }}
            views={getViewsForPattern(pattern) as any} // DateView is not exported
            format={pattern}
            closeOnSelect
            value={answer}
            slotProps={{
              field: {
                clearable: true,
              },
              textField: {
                sx: textFieldSxProps,
                disabled: true, // Disable text input, only date picker is allowed
              },
            }}
          />
        );
      case TIME_HH_MM:
        return (
          <DesktopTimePicker
            onChange={value => setValue(name, value)}
            onOpen={() => {
              setIsTimePickerOpen(true);
              isOpeningRef.current = false;
            }}
            onClose={() => {
              setIsTimePickerOpen(false);
              removeFocus();
            }}
            timeSteps={{ minutes: 1 }}
            open
            views={getViewsForPattern(pattern) as any}
            closeOnSelect
            format={pattern}
            value={answer}
            slotProps={{
              textField: {
                disabled: true,
                onMouseDownCapture: () => {
                  // Detect the click that will open the picker before blur fires
                  isOpeningRef.current = true;
                },
                onBlur: () => {
                  // Skip blur caused by opening the picker
                  if (isOpeningRef.current || isTimePickerOpen) {
                    return;
                  }
                  removeFocus();
                },
                sx: textFieldSxProps,
              },
              popper: {
                sx: {
                  '& .MuiMultiSectionDigitalClockSection-root': {
                    scrollbarWidth: 'thin',
                    '&::-webkit-scrollbar': {
                      width: scrollbarWidth,
                    },
                  },
                  '& .MuiMultiSectionDigitalClockSection-item': {
                    fontSize: datePickerFontSize,
                    fontWeight: datePickerFontWeight,
                    color: theme.palette.new.text.neutral.default,
                  },
                  '& .MuiMultiSectionDigitalClockSection-item.Mui-selected': {
                    bgcolor: primaryHugoColor,
                    color: bgWhite,
                  },
                },
              },
            }}
            inputRef={inputRef as RefObject<HTMLInputElement>}
          />
        );
      case DATETIME_DD_MM_YYYY_HH_MM_SS:
        return (
          <DesktopDateTimePicker
            value={answer}
            open
            timeSteps={{ minutes: 1 }}
            format={pattern}
            onChange={value => {
              setValue(name, value);
            }}
            onClose={removeFocus}
            slotProps={{
              field: {
                clearable: true,
              },
              textField: {
                disabled: true,
                sx: textFieldSxProps,
              },
              day: {
                sx: {
                  fontSize: datePickerFontSize,
                  fontWeight: datePickerFontWeight,
                  color: theme.palette.new.text.neutral.default,
                  '&.Mui-selected': {
                    backgroundColor: primaryHugoColor,
                    color: bgWhite,
                  },
                  '&:hover.Mui-selected': {
                    bgcolor: primaryHugoColor,
                  },
                },
              },
              yearButton: {
                sx: {
                  fontSize: datePickerFontSize,
                  fontWeight: datePickerFontWeight,
                  color: theme.palette.new.text.neutral.default,
                  '&.Mui-selected': {
                    bgcolor: primaryHugoColor,
                    color: bgWhite,
                  },
                },
              },
              popper: {
                sx: {
                  '& .MuiMultiSectionDigitalClockSection-root': {
                    scrollbarWidth: 'thin',
                    '&::-webkit-scrollbar': {
                      width: scrollbarWidth,
                    },
                  },
                  '& .MuiMultiSectionDigitalClockSection-item': {
                    fontSize: datePickerFontSize,
                    fontWeight: datePickerFontWeight,
                    color: theme.palette.new.text.neutral.default,
                  },
                  '& .MuiMultiSectionDigitalClockSection-item.Mui-selected': {
                    bgcolor: primaryHugoColor,
                    color: bgWhite,
                  },
                },
              },
            }}
            sx={{
              backgroundColor: theme.palette.new.background.layout.tertiary,
              opacity: 0.8,
            }}
          />
        );
      default:
        return null;
    }
  }

  const containerSxProps = getFieldContainerSxProps(
    hasErrors,
    dimensionSxProps,
    theme,
  );

  // Has answer and not focused
  if (hasAnswer) {
    return (
      <HuTooltip {...getTooltipProps()}>
        <Stack
          onClick={handleFocus}
          sx={{
            justifyContent: 'center',
            backgroundColor: hasErrors
              ? theme.palette.new.background.feedback.error
              : theme.palette.new.background.layout.tertiary,
            ...containerSxProps,
          }}
        >
          <Typography
            sx={{
              width: 1,
              ...textStyles,
              ...TYPOGRAPHY_OVERFLOW_SX_PROPS,
            }}
          >
            {format(answer, pattern, {
              locale: getCurrentLocale(user),
            })}
          </Typography>
        </Stack>
      </HuTooltip>
    );
  }

  // No answer and not focused
  return (
    <HuTooltip {...getTooltipProps()}>
      <Stack
        onClick={handleFocus}
        sx={{
          alignItems: 'center',
          gap: 0.5,
          flexDirection: 'row',
          backgroundColor: hasErrors
            ? theme.palette.new.background.feedback.error
            : theme.palette.new.background.layout.brand,
          ...containerSxProps,
        }}
      >
        <Typography sx={{ ...TYPOGRAPHY_OVERFLOW_SX_PROPS, ...textStyles }}>
          {title}
        </Typography>
        {required && (
          <Typography
            sx={{
              ...textStyles,
              color: ({ palette }) => palette.new.text.feedback.error,
            }}
          >
            *
          </Typography>
        )}
      </Stack>
    </HuTooltip>
  );
};

export default DateField;
