import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation } from 'react-query';
import { useNavigate } from 'react-router';

import { useModal } from '@material-hu/hooks/useModal';
import Stack from '@material-hu/mui/Stack';

import Button from '@material-hu/components/design-system/Buttons/Button';
import Dialog from '@material-hu/components/design-system/Dialog';
import ProgressBar from '@material-hu/components/design-system/ProgressIndicators/ProgressBar';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';

import { queryClient } from 'src/config/react-query';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import * as timeTrackingService from 'src/services/timeTrackingService';
import { NightShiftAssignmentMode } from 'src/types/timeTracking';
import { UserSelection } from 'src/types/user';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { LogEvents, logEvent } from 'src/utils/logging';
import { WEEKDAYS, formatUTCDate } from 'src/utils/timeUtils';

import FormSelectUsers from 'src/components/FormSelectUsers';

import useTimeTrackingSettings from '../../hooks/useTimeTrackingSettings';
import { timeTrackingKeys } from '../../queries';
import { timeTrackingRoutes } from '../../routes';
import SectionHeader from '../../SectionHeader';
import EffectiveDates from '../components/EffectiveDates';
import GeneralDataStep from '../components/GeneralDataStep';
import WorkdayStep from '../components/WorkdayStep';
import { ScheduleFields, ScheduleMode } from '../types';
import { getCreateParams } from '../utils';

const initialDays = WEEKDAYS.slice(0, 5);

const CreateSchedule = () => {
  const [step, setStep] = useState(0);
  const { t } = useLokaliseTranslation([
    'work_schedules',
    'time_tracker',
    'general',
  ]);
  const HuGoThemeProvider = useHuGoTheme();
  const navigate = useNavigate();
  const { enqueueSnackbar } = useHuSnackbar();
  const showGeneralError = useGeneralError();

  const form = useForm<ScheduleFields>({
    defaultValues: {
      name: '',
      description: '',
      // Select week days by default
      scheduledDays: initialDays.map(d => ({
        dayOfWeek: d,
        timeSlots: [
          {
            startTime: undefined,
            endTime: undefined,
          },
        ],
      })),
      generalTimeSlots: [
        {
          startTime: undefined,
          endTime: undefined,
        },
      ],
      userMode: UserSelection.NONE,
      scheduleMode: ScheduleMode.general,
      userIds: [],
      startDate: new Date(),
      endDate: null,
    },
    mode: 'onChange',
  });
  const { userMode } = form.watch();
  const { formState } = form;

  const {
    mutate: createScheduleMutation,
    isLoading,
    reset: resetMutation,
  } = useMutation(
    () => {
      const params = getCreateParams(form.getValues());
      return timeTrackingService.createSchedule(params);
    },
    {
      onSuccess: () => {
        const {
          userIds,
          userMode: selectedUserMode,
          startDate,
          endDate,
        } = form.getValues();

        const totalUserCount =
          selectedUserMode === UserSelection.ALL_USERS ? -1 : userIds?.length;

        queryClient.invalidateQueries(timeTrackingKeys.schedules());
        logEvent(LogEvents.TIME_TRACKING_SCHEDULE_CREATED, {
          date: formatUTCDate(new Date()),
        });

        if (totalUserCount) {
          logEvent(LogEvents.TIME_TRACKING_SCHEDULE_ASSIGNED, {
            userCount: totalUserCount,
            startDate: formatUTCDate(startDate),
            endDate: endDate ? formatUTCDate(endDate) : null,
          });
        }

        enqueueSnackbar({
          title: t('work_schedules:CREATE_SUCCESS'),
          variant: 'success',
        });
        navigate(timeTrackingRoutes.workSchedulesList());
      },
      onError: err => {
        showGeneralError(err, t('work_schedules:CREATE_ERROR'));
        resetMutation();
      },
    },
  );

  const { data: timeTrackingSettings } = useTimeTrackingSettings();
  const enabledNightShifts =
    timeTrackingSettings?.nightShiftAssignment ===
    NightShiftAssignmentMode.SCHEDULE_INIT;

  const steps = [
    {
      label: t('work_schedules:general_step_title'),
      Component: (
        <GeneralDataStep
          nameSubtitle={t('work_schedules:schedule_name')}
          nameProps={{
            placeholder: t('work_schedules:write_schedule_name'),
          }}
          descriptionSubtitle={t('work_schedules:schedule_description')}
          descriptionProps={{
            label: t('work_schedules:schedule_description_label'),
            placeholder: t('work_schedules:write_schedule_description'),
          }}
        />
      ),
    },
    {
      label: t('work_schedules:workday_title'),
      Component: <WorkdayStep enabledNightShifts={enabledNightShifts} />,
    },
    {
      label: t('work_schedules:collaborators'),
      Component: (
        <Stack
          sx={{
            flex: 1,
            pb: 4,
            width: '100%',
          }}
        >
          <FormSelectUsers
            participantsLabel={t('work_schedules:participants')}
            searchLabel={t('work_schedules:search_employees')}
            translationPrefix="work_schedules:schedule_assignments"
          />
          {userMode !== UserSelection.NONE && <EffectiveDates />}
        </Stack>
      ),
    },
  ];
  const isFirstStep = step === 0;
  const isLastStep = step === steps.length - 1;
  const currentStep = steps[step];

  const confirmChangesModal = useModal(
    Dialog,
    { maxWidth: 'sm' },
    {
      title: t('work_schedules:confirm_schedule_title'),
      textBody: t('work_schedules:confirm_schedule_description'),
      primaryButtonProps: {
        children: t('general:confirm'),
        onClick: () => {
          confirmChangesModal?.closeModal();
          createScheduleMutation();
        },
      },
      secondaryButtonProps: {
        children: t('general:cancel'),
        onClick: () => {
          confirmChangesModal.closeModal();
        },
      },
    },
  );

  const nextStep = () => {
    if (isLastStep) {
      confirmChangesModal.showModal();
      return;
    }
    form.trigger().then(isValid => {
      if (isValid) {
        setStep(step + 1);
      }
    });
  };

  const previousStep = () => {
    setStep(step - 1);
    // Used to reset the form validity, without this in case the current step has invalid fields
    // and the user goes back it will persist the invalid state
    form.reset(undefined, { keepValues: true, keepErrors: true });
  };

  return (
    <HuGoThemeProvider>
      {confirmChangesModal?.modal}
      <FormProvider {...form}>
        <Stack
          sx={{
            backgroundColor: ({ palette }) =>
              palette.new.background.layout.default,
            minHeight: '100%',
          }}
        >
          <SectionHeader
            goBack={() => {
              navigate(timeTrackingRoutes.workSchedulesList());
            }}
            title={t('work_schedules:new_work_schedule')}
          />
          <Stack
            sx={{
              height: '100%',
              flex: 1,
              '& > *': { px: '18%' },
            }}
          >
            <Stack sx={{ flex: 1, pb: 5, pt: 3 }}>
              <ProgressBar
                total={steps.length}
                current={step + 1}
                variant="determinate"
                title={currentStep.label}
                description={t('time_tracker:policies.step_description', {
                  step: step + 1,
                  totalSteps: steps.length,
                })}
                sx={{ mb: 3 }}
              />
              {currentStep.Component}
            </Stack>
            <Stack
              sx={{
                flexDirection: 'row',
                justifyContent: isFirstStep ? 'flex-end' : 'space-between',
                backgroundColor: theme =>
                  theme.palette.new.background.layout.tertiary,
                boxShadow: theme => theme.shadows[2],
                py: 2,
                width: '100%',
              }}
            >
              {!isFirstStep && (
                <Button
                  variant="secondary"
                  size="large"
                  onClick={previousStep}
                >
                  {t('general:back')}
                </Button>
              )}
              <Button
                variant="primary"
                size="large"
                disabled={!formState.isValid || isLoading}
                loading={isLoading}
                onClick={nextStep}
              >
                {t(isLastStep ? 'work_schedules:add_schedule' : 'general:next')}
              </Button>
            </Stack>
          </Stack>
        </Stack>
      </FormProvider>
    </HuGoThemeProvider>
  );
};

export default CreateSchedule;
