import { type FC, useEffect, useMemo } from 'react';
import { FormProvider, type UseFormReset, useForm } from 'react-hook-form';

import { useModal } from '@material-hu/hooks/useModal';
import { IconArrowBack, IconChevronDown } from '@material-hu/icons/tabler';
import Accordion from '@material-hu/mui/Accordion';
import AccordionDetails from '@material-hu/mui/AccordionDetails';
import AccordionSummary from '@material-hu/mui/AccordionSummary';
import Box from '@material-hu/mui/Box';
import Divider from '@material-hu/mui/Divider';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';

import Alert from '@material-hu/components/design-system/Alert';
import HuBadge from '@material-hu/components/design-system/Badge';
import Button from '@material-hu/components/design-system/Buttons/Button';
import HuDialog from '@material-hu/components/design-system/Dialog';
import HuPills from '@material-hu/components/design-system/Pills';

import {
  CREATING_ENTRY_ID,
  REMOTE_WORK_SITE_VALUE,
} from 'src/pages/dashboard/timeTracking/constants';
import {
  type DaySummary,
  type DirtyEntryFormFields,
  type EntryFormFields,
  EntrySource,
  EntryType,
  type PairedEntry,
  type SiteCoordinates,
  type SiteLocation,
  type TimePairs,
  type UserSite,
} from 'src/types/timeTracking';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { parseEntryName } from 'src/utils/timeTracking';

import EntryAction from './EntryAction';
import EntryDetail from './EntryDetail';
import { useAutocloseDescription } from './useAutocloseDescription';

type Props = {
  autoCloseMode?: DaySummary['autoCloseMode'];
  entryPair: PairedEntry;
  disabled: boolean;
  handleEditInit: (id: string | undefined) => void;
  editingTimeSlot: string | undefined;
  ongoingEntry: boolean;
  isOpen: boolean;
  handleAccordionToggle: (id: string | undefined) => void;
  onKeepAccordionOpen: (id: string) => void;
  summaryDay: string;
  onEntryUpdate: (
    formValues: EntryFormFields,
    dirtyFields: DirtyEntryFormFields,
    resetFormFields: UseFormReset<EntryFormFields>,
  ) => void;
  isLoading: boolean;
  onEntryDeletion: (id: string) => void;
  reservedCycles: TimePairs[];
  enableNightShift: boolean;
  userId: number;
  userSites: UserSite[];
  onSiteClick?: (
    siteId: number | null,
    siteName: string,
    location: SiteLocation,
    markingLocation: SiteCoordinates | null,
    entrySource: EntrySource,
    entryType: EntryType,
  ) => void;
  onSelectedSiteChange?: (siteId: number, entryType: EntryType) => void;
  onFormValuesChange?: (
    formValues: EntryFormFields,
    entryPairId: string,
    siteIds: { start: { siteId: number }; end: { siteId: number } },
  ) => void;
  enableRemoteWork?: boolean;
  isDeactivated?: boolean;
};

const PLUS_ONE = '+1';

const EntryAccordion: FC<Props> = props => {
  const {
    autoCloseMode,
    disabled,
    editingTimeSlot,
    handleEditInit,
    entryPair,
    ongoingEntry,
    isOpen,
    handleAccordionToggle,
    onKeepAccordionOpen,
    summaryDay,
    onEntryUpdate,
    isLoading,
    onEntryDeletion,
    reservedCycles,
    enableNightShift,
    userId,
    userSites,
    onSiteClick,
    onSelectedSiteChange,
    onFormValuesChange,
    enableRemoteWork,
    isDeactivated,
  } = props;
  const { t } = useLokaliseTranslation('time_tracker');
  const { palette } = useTheme();
  const startEntry = entryPair.start;
  const endEntry = entryPair.end;

  const { autoClosed, description: autocloseDescription } =
    useAutocloseDescription({
      autoCloseMode,
      startEntry,
      endEntry,
    });

  const parseEntryHour = (entryTimestamp: Date) => {
    const summaryDate = new Date(`${summaryDay}T00:00:00`);
    summaryDate.setHours(entryTimestamp.getHours());
    summaryDate.setMinutes(entryTimestamp.getMinutes());
    return summaryDate;
  };

  const toEntryField = (entry: PairedEntry['start']) => ({
    time: entry?.time ? parseEntryHour(new Date(entry.time)) : undefined,
    siteId: entry?.isRemoteWork ? REMOTE_WORK_SITE_VALUE : entry?.siteId || -1,
    kioskId: entry?.kioskId ? parseInt(entry.kioskId) : undefined,
    comment: entry?.comment || '',
  });

  const buildEntryFormValues = (): EntryFormFields => ({
    start: toEntryField(startEntry),
    end: toEntryField(endEntry),
  });

  const defaultFormValues: EntryFormFields = useMemo(
    () => buildEntryFormValues(),
    [
      startEntry?.time,
      startEntry?.siteId,
      startEntry?.kioskId,
      startEntry?.comment,
      startEntry?.isRemoteWork,
      endEntry?.time,
      endEntry?.siteId,
      endEntry?.kioskId,
      endEntry?.comment,
      endEntry?.isRemoteWork,
      summaryDay,
    ],
  );

  const form = useForm<EntryFormFields>({
    defaultValues: defaultFormValues,
    mode: 'onSubmit',
  });
  const {
    formState: { errors, dirtyFields },
    handleSubmit,
    reset,
  } = form;

  const { end, start } = form.watch();

  // Notify parent about form values changes
  useEffect(() => {
    if (onFormValuesChange) {
      const allFormValues = form.getValues();
      onFormValuesChange(allFormValues, entryPair.id, {
        start: { siteId: start.siteId },
        end: { siteId: end.siteId },
      });
    }
  }, [
    start.siteId,
    end.siteId,
    start.time,
    end.time,
    start.comment,
    end.comment,
    start.kioskId,
    end.kioskId,
    onFormValuesChange,
    form,
    entryPair.id,
  ]);

  // Update the map when this entry's site changes while it's being edited. Gate
  // on "this pair is being edited", not dirty fields: re-selecting the original
  // value clears dirty but must still update the map. The gate also stops other
  // pairs' effects (which re-run when the shared onSelectedSiteChange identity
  // changes on map open) from overwriting the shown site.
  const isEditingThisPair = editingTimeSlot === entryPair.id;
  useEffect(() => {
    if (
      onSelectedSiteChange &&
      isEditingThisPair &&
      start.siteId &&
      start.siteId !== -1
    ) {
      onSelectedSiteChange(start.siteId, EntryType.START);
    }
  }, [start.siteId, onSelectedSiteChange, isEditingThisPair]);

  useEffect(() => {
    if (
      onSelectedSiteChange &&
      isEditingThisPair &&
      end.siteId &&
      end.siteId !== -1
    ) {
      onSelectedSiteChange(end.siteId, EntryType.END);
    }
  }, [end.siteId, onSelectedSiteChange, isEditingThisPair]);

  const deleteModal = useModal(
    () => (
      <HuDialog
        onClose={deleteModal.closeModal}
        title={t('delete_register_title')}
        textBody={t('delete_register_warning')}
        primaryButtonProps={{
          children: t('confirm'),
          onClick: () => {
            onEntryDeletion(entryPair.id);
          },
          loading: isLoading,
        }}
        secondaryButtonProps={{
          children: t('cancel'),
          sx: { textTransform: 'none' },
          onClick: deleteModal.closeModal,
        }}
      />
    ),
    { maxWidth: 'sm' },
  );

  const handleAccordion = (id: string) => (_: unknown, expanded: boolean) => {
    handleAccordionToggle(expanded || editingTimeSlot === id ? id : undefined);
  };

  const isCreatingEntry = editingTimeSlot === CREATING_ENTRY_ID;

  const handleDiscardChanges = () => {
    const originalValues = buildEntryFormValues();
    reset(originalValues);
    // Discard exits edit mode in the same update, so the gated effects above
    // won't re-fire — revert the map's site explicitly (only the shown entry).
    onSelectedSiteChange?.(originalValues.start.siteId, EntryType.START);
    onSelectedSiteChange?.(originalValues.end.siteId, EntryType.END);

    if (isCreatingEntry) {
      onEntryDeletion(entryPair.id);
    } else {
      // Keep accordion open when exiting edit mode
      onKeepAccordionOpen(entryPair.id);
      handleEditInit(undefined);
    }
  };

  const startLocationIncidence =
    startEntry?.locationIncidence && !startEntry?.isRemoteWork;
  const endLocationIncidence =
    endEntry?.locationIncidence && !endEntry?.isRemoteWork;
  const showAlertIcon =
    autoClosed || startLocationIncidence || endLocationIncidence;
  const timeSlotBeingEdited = entryPair.id === editingTimeSlot;

  const entryTimes = parseEntryName(
    startEntry?.time,
    endEntry?.time,
    ongoingEntry,
    t,
  );

  const ERROR_WORDINGS = {
    required: {
      title: t('error_missing_title'),
      message: t('error_missing_message'),
    },
    checkValidFormatDate: {
      title: t('error_invalid_title'),
      message: t('error_invalid_message'),
    },
    validateDateOrder: {
      title: t('error_inverted_title'),
      message: t('error_inverted_message'),
    },
    validateDatesCollision: {
      title: t('error_collision_title'),
      message: t('error_collision_message'),
    },
    openCycleWithFutureEntries: {
      title: t('error_collision_title'),
      message: t('error_collision_message'),
    },
    futureEntry: {
      title: t('error_future_title'),
      message: t('error_future_message'),
    },
    sameTypeEntries: {
      title: t('error_collision_title'),
      message: t('error_collision_message'),
    },
    noRepeated: {
      title: t('error_repeated_title'),
      message: t('error_repeated_message'),
    },
  };

  const generateErrorAlert = () => {
    const error = errors.end || errors.start;
    const errorType = error?.time?.type as keyof typeof ERROR_WORDINGS;
    return errorType ? ERROR_WORDINGS[errorType] : undefined;
  };

  const errorAlert = errors && generateErrorAlert();
  const entryWithNightShift =
    enableNightShift && end.time && start.time && end.time < start.time;
  const showNightShiftAlert =
    !errorAlert && entryWithNightShift && editingTimeSlot;

  return (
    <FormProvider {...form}>
      {deleteModal.modal}
      <Accordion
        key={entryPair.id}
        disabled={disabled}
        expanded={isOpen || editingTimeSlot === entryPair.id}
        onChange={handleAccordion(entryPair.id)}
        sx={{
          border: 'none',
          borderRadius: ({ spacing }) => spacing(1),
          boxShadow: 'none',
          '&:before': {
            display: 'none',
          },
          '&.Mui-disabled': {
            borderTop: 'unset',
            cursor: 'not-allowed',
            opacity: 0.6,
          },
        }}
      >
        <AccordionSummary
          expandIcon={editingTimeSlot ? null : <IconChevronDown />}
          sx={{
            backgroundColor: palette.new.background.layout.default,
            borderRadius: ({ spacing }) => spacing(1),
            height: '72px',
            '&.Mui-expanded': {
              borderBottomLeftRadius: 0,
              borderBottomRightRadius: 0,
            },
          }}
        >
          <Stack
            sx={{
              alignItems: 'center',
              flexDirection: 'row',
              justifyContent: 'space-between',
              mr: 1,
              width: '100%',
            }}
          >
            <HuBadge
              anchorOrigin={{
                horizontal: 'left',
                vertical: 'top',
              }}
              badgeContent={1}
              color="success"
              variant="dot"
              invisible={!ongoingEntry}
              sx={{
                '.MuiBadge-badge': {
                  top: '50%',
                },
              }}
            >
              <Typography
                variant="globalS"
                fontWeight="fontWeightSemiBold"
                sx={{ pl: 1 }}
              >
                {entryTimes}
              </Typography>
              {entryWithNightShift && !timeSlotBeingEdited && (
                <Typography
                  variant="globalXXS"
                  fontWeight="fontWeightSemiBold"
                  sx={{
                    color: palette.new.text.feedback.info,
                    ml: 0.5,
                  }}
                >
                  {PLUS_ONE}
                </Typography>
              )}
            </HuBadge>
            {showAlertIcon && !timeSlotBeingEdited && (
              <HuPills
                label={t('incidence')}
                type="warning"
                sx={{ alignSelf: 'flex-end' }}
              />
            )}
            {timeSlotBeingEdited && !isCreatingEntry && (
              <Button
                variant="secondary"
                startIcon={<IconArrowBack size={16} />}
                onClick={e => {
                  e.stopPropagation();
                  handleDiscardChanges();
                }}
                disabled={isLoading}
                sx={{ fontSize: 14 }}
              >
                {t('exit_without_saving')}
              </Button>
            )}
          </Stack>
        </AccordionSummary>
        <form
          onSubmit={handleSubmit(values =>
            onEntryUpdate(values, dirtyFields, reset),
          )}
          noValidate
        >
          <Box
            sx={{
              borderLeft: ({ palette }) =>
                `1px solid ${palette.new.border.neutral.default}`,
              borderRight: ({ palette }) =>
                `1px solid ${palette.new.border.neutral.default}`,
              borderBottom: ({ palette }) =>
                `1px solid ${palette.new.border.neutral.default}`,
              borderBottomLeftRadius: ({ spacing }) => spacing(1),
              borderBottomRightRadius: ({ spacing }) => spacing(1),
              overflow: 'hidden',
            }}
          >
            <AccordionDetails
              sx={{
                pt: 2,
              }}
            >
              <EntryDetail
                data={startEntry || {}}
                type={EntryType.START}
                pairId={entryPair.id}
                isEditing={timeSlotBeingEdited}
                summaryDay={summaryDay}
                reservedCycles={reservedCycles}
                enableNightShift={enableNightShift}
                userId={userId}
                userSites={userSites}
                onSiteClick={onSiteClick}
                enableRemoteWork={enableRemoteWork}
              />
              <Divider sx={{ borderWidth: 0.5, my: 2 }} />
              <EntryDetail
                data={endEntry || {}}
                type={EntryType.END}
                pairId={entryPair.id}
                isEditing={timeSlotBeingEdited}
                summaryDay={summaryDay}
                reservedCycles={reservedCycles}
                enableNightShift={enableNightShift}
                userId={userId}
                userSites={userSites}
                onSiteClick={onSiteClick}
                enableRemoteWork={enableRemoteWork}
              />
              {!timeSlotBeingEdited && autoClosed && (
                <Alert
                  severity="warning"
                  title={t('forgot_time_check')}
                  description={autocloseDescription}
                  sx={{ my: 2 }}
                />
              )}
              {timeSlotBeingEdited && errorAlert && (
                <Alert
                  severity="error"
                  title={errorAlert.title}
                  description={errorAlert.message}
                  sx={{ my: 2 }}
                />
              )}
              {showNightShiftAlert && (
                <Alert
                  severity="info"
                  title={t('night_shift')}
                  description={t('night_shift_hint')}
                  sx={{ my: 2 }}
                />
              )}
            </AccordionDetails>
            <EntryAction
              editingTimeSlot={editingTimeSlot || null}
              entryId={entryPair.id}
              handleEditInit={handleEditInit}
              isLoading={isLoading}
              showDeleteModal={deleteModal.showModal}
              onEntryDeletion={() => {
                onEntryDeletion(entryPair.id);
              }}
              isDeactivated={isDeactivated}
            />
          </Box>
        </form>
      </Accordion>
    </FormProvider>
  );
};

export default EntryAccordion;
