import { useEffect, useId, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation, useQuery } from 'react-query';
import { useParams } from 'react-router-dom';

import { differenceInSeconds } from 'date-fns';
import debounce from 'lodash-es/debounce';
import isNil from 'lodash-es/isNil';
import { IconArrowLeft } from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuAlert from '@material-hu/components/design-system/Alert';
import HuAvatar from '@material-hu/components/design-system/Avatar';
import Button from '@material-hu/components/design-system/Buttons/Button';
import useSnackbar from '@material-hu/components/design-system/Snackbar';
import {
  useDialogLayer,
  useDialogLayerItem,
} from '@material-hu/components/layers/Dialogs';
import {
  useDrawerLayer,
  useDrawerLayerItem,
} from '@material-hu/components/layers/Drawers';
import HuStepper from '@material-hu/components/design-system/Stepper';
import HuTabs from '@material-hu/components/design-system/Tabs';
import HuTitle from '@material-hu/components/design-system/Title';

import { logEvent } from 'src/config/logging';
import {
  checkReviewAsCompleted,
  invalidateAllCycleStats,
  invalidateLeaderUsers,
  invalidateReview,
  performanceKeys,
} from 'src/pages/dashboard/performance/queries';
import {
  completeReview,
  editReview,
  getReviewCycle,
  getReviewDetail,
  requestReviewEdition,
  shareReview,
} from 'src/pages/dashboard/performance/services';
import {
  DeliveryStatus,
  type ReviewBody,
  ReviewCycleStatus,
  ReviewDirection,
  type ReviewFormValues,
} from 'src/pages/dashboard/performance/types';
import {
  createReviewAnswers,
  getEffectiveReviewForm,
  getIsFinished,
  getIsReviewShared,
  isDownwardReview,
  splitReviewInputs,
} from 'src/pages/dashboard/performance/utils';
import { EventName, SharedReviewOrigin } from 'src/types/amplitude';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getFullName, getInitials } from 'src/utils/userUtils';

import CalibrationComparisonDrawer from '../../CalibrationDetail/components/CalibrationComparisonDrawer';
import { useReviewCalibrationComparison } from '../../hooks/useReviewCalibrationComparison';
import ReviewInputSection, {
  ReviewInputSectionType,
  reviewSectionTitleTranslationKey,
} from '../../components/ReviewInputSection';
import ReviewNextStepButton from '../../components/ReviewNextStepButton';
import TemplateDescription from '../../components/TemplateDescription';
import { usePerformanceReview } from '../../PerformanceReviewContext';

import CompletedReviewCard from './CompletedReviewCard';
import RequestEditionDrawerContent from './RequestEditionDrawerContent';
import {
  AUTOSAVE_DEBOUNCE_MS,
  getFinishReviewModalDescriptionKey,
  getReasonTranslationKey,
} from './reviewFromUtils';

type ReviewFormProps = {
  reviewId: number;
};

const ReviewForm = ({ reviewId }: ReviewFormProps) => {
  const { id } = useParams();
  const cycleId: string = id ?? '';
  const { t } = useLokaliseTranslation(['performance', 'competencies']);
  const { enqueueSnackbar } = useSnackbar();

  const { nextReview, reviews, setAllReviewsCompleted, setSelectedReview } =
    usePerformanceReview();

  const form = useForm<ReviewFormValues>();
  const [selectedReason, setSelectedReason] = useState<number | null>(null);

  const {
    handleSubmit,
    reset,
    formState: { isSubmitting, isValid },
    watch,
  } = form;

  // biome-ignore lint/correctness/useExhaustiveDependencies: Run only on mount
  useEffect(() => {
    const savedData = localStorage.getItem(`${reviewId}`);
    if (!isNil(savedData)) {
      try {
        const parsed = JSON.parse(savedData);
        if (parsed?.reviewId === reviewId && !isNil(parsed?.data)) {
          reset(parsed.data);
        } else {
          localStorage.removeItem(`${reviewId}`);
        }
      } catch {
        localStorage.removeItem(`${reviewId}`);
      }
    }
  }, []);

  useEffect(() => {
    const save = debounce(
      (values: Parameters<Parameters<typeof watch>[0]>[0]) => {
        try {
          localStorage.setItem(
            `${reviewId}`,
            JSON.stringify({ reviewId, data: values }),
          );
        } catch {
          // localStorage quota exceeded - auto-save is best effort, skip silently
        }
      },
      AUTOSAVE_DEBOUNCE_MS,
    );

    const { unsubscribe } = watch(values => save(values));
    return () => {
      unsubscribe();
      save.cancel();
    };
  }, [watch, reviewId]);

  const startTime = useMemo(() => new Date(), []);

  const { data: cycle } = useQuery(
    performanceKeys.cycle(cycleId),
    () => getReviewCycle(cycleId),
    { select: response => response.data },
  );

  const {
    data: review,
    isLoading: reviewLoading,
    refetch,
  } = useQuery(
    performanceKeys.review(cycleId, reviewId),
    () => getReviewDetail(cycleId, reviewId),
    {
      cacheTime: 0,
      select: response => response.data,
    },
  );

  const isFinished = getIsFinished(
    review?.status || ReviewCycleStatus.IN_PROGRESS,
  );
  const requestedEdition = review?.status === ReviewCycleStatus.EDIT_REQUESTED;
  const pendingEdition = review?.status === ReviewCycleStatus.EDIT_PENDING;

  const { mutate, isLoading: isLoadingCompleteReview } = useMutation(
    (body: ReviewBody) =>
      pendingEdition
        ? editReview(cycleId, reviewId, body)
        : completeReview(cycleId, reviewId, body),
    {
      onSuccess: response => {
        const reviewLayout = document.getElementById('review-layout');
        if (reviewLayout) {
          reviewLayout.scrollTo(0, 0);
        }
        checkReviewAsCompleted(cycleId, reviewId);
        invalidateReview(cycleId, reviewId);
        invalidateAllCycleStats(cycleId);
        invalidateLeaderUsers(cycleId);
        logEvent(EventName.PERF_REV_REVIEW_COMPLETED, {
          cycleId,
          reviewId: reviewId || 0,
          direction: response.data.type,
        });
        reset();
        if (!isNil(localStorage.getItem(`${reviewId}`))) {
          localStorage.removeItem(`${reviewId}`);
        }
        const isLastReview = reviews
          .filter(reviewDetail => reviewDetail.reviewId !== reviewId)
          .every(reviewDetail => reviewDetail.answered);

        if (isLastReview) {
          setAllReviewsCompleted(true);
          setSelectedReview(null);
        } else {
          nextReview();
        }
        enqueueSnackbar({
          title: t('review_completed.success'),
          variant: 'success',
        });
      },
    },
  );

  const { mutate: shareReviewMutate, isLoading: isSharingReview } = useMutation(
    () => shareReview(cycleId, review?.reviewedId as number, watch('summary')),
    {
      onSuccess: () => {
        logEvent(EventName.PERF_REV_REVIEW_SHARED, {
          cycleId,
          reviewId,
          origin: SharedReviewOrigin.BOSS,
        });
        invalidateReview(cycleId, reviewId);
        invalidateAllCycleStats(cycleId);
        invalidateLeaderUsers(cycleId);
        enqueueSnackbar({ title: t('form.share_success'), variant: 'success' });
        reset();
        if (!isNil(localStorage.getItem(`${reviewId}`))) {
          localStorage.removeItem(`${reviewId}`);
        }
      },
    },
  );

  const { mutate: requestEditionMutate, isLoading: isRequestingEdition } =
    useMutation(
      () =>
        requestReviewEdition(
          cycleId,
          reviewId,
          reasonOptions.find(r => r.value === selectedReason)?.label,
        ),
      {
        onSuccess: () => {
          refetch();
          enqueueSnackbar({
            title: t('form.share_success'),
            variant: 'success',
          });
          reset();
          if (!isNil(localStorage.getItem(`${reviewId}`))) {
            localStorage.removeItem(`${reviewId}`);
          }
        },
      },
    );

  const { withSummary, summary, canBeShared } = cycle || {};
  const { reviewed, answered: firstAnswered, shareStatus } = review || {};

  const canBeSharedBeforeCycleFinish =
    cycle?.canBeSharedBeforeCycleFinish &&
    isDownwardReview(review?.type || ReviewDirection.AUTO_REVIEW);

  const answered = firstAnswered && !pendingEdition;
  const effectiveForm = getEffectiveReviewForm(review);
  const reviewInputs = effectiveForm?.questions || [];
  const { formQuestions, goalQuestions, competencyQuestions } = useMemo(
    () => splitReviewInputs(reviewInputs),
    [reviewInputs],
  );

  const description = effectiveForm?.description || null;
  const isLeader = review?.type === ReviewDirection.SUBORDINATE_REVIEW;
  const isSelfReview = review?.type === ReviewDirection.AUTO_REVIEW;

  const isOmitted = review?.status === ReviewCycleStatus.OMITTED;

  const isFormDisabled = answered || isOmitted || requestedEdition;

  const reviewedFullName = getFullName(reviewed || {});
  const firstName = reviewed?.firstName;

  const submit = (values: ReviewFormValues) => {
    const endTime = new Date();
    const fillingTime = differenceInSeconds(endTime, startTime);

    const questionAnswers = createReviewAnswers(
      values,
      review?.form?.questions || [],
    ) as ReviewBody['questionAnswers'];

    mutate({
      fillingTime,
      questionAnswers,
    });
  };

  const canSubmit =
    isValid &&
    !isLoadingCompleteReview &&
    !isSubmitting &&
    !isSharingReview &&
    !requestedEdition;

  const reviewShared = getIsReviewShared(
    shareStatus || DeliveryStatus.NOT_SHARED,
  );

  const canRequestEdition =
    cycle?.status !== ReviewCycleStatus.FINISHED &&
    !reviewShared &&
    !requestedEdition &&
    // When the subordinate review is already calibrated, the calibration
    // suplants it — there's nothing to request an edit on.
    !review?.calibrationForm;

  const showShareButton =
    canBeShared &&
    isLeader &&
    !isSelfReview &&
    !isOmitted &&
    !reviewShared &&
    (canBeSharedBeforeCycleFinish || isFinished);

  const showSharedMessage = !showShareButton && !isSelfReview && reviewShared;

  const canViewGoalDetails = review?.loggedUserCanViewGoalsOfReviewed || false;

  const availableTabs = useMemo(() => {
    const tabs: ReviewInputSectionType[] = [];
    if (formQuestions.length > 0) tabs.push(ReviewInputSectionType.FORM);
    if (goalQuestions.length > 0) tabs.push(ReviewInputSectionType.GOAL);
    if (competencyQuestions.length > 0)
      tabs.push(ReviewInputSectionType.COMPETENCY);
    return tabs;
  }, [formQuestions.length, goalQuestions.length, competencyQuestions.length]);

  const [currentStepIndex, setCurrentStepIndex] = useState(0);

  useEffect(() => {
    if (availableTabs.length === 0) return;
    setCurrentStepIndex(prev => (prev >= availableTabs.length ? 0 : prev));
  }, [availableTabs]);

  // biome-ignore lint/correctness/useExhaustiveDependencies: scroll on step change
  useEffect(() => {
    const reviewLayout = document.getElementById('review-layout');
    if (reviewLayout) reviewLayout.scrollTo(0, 0);
  }, [currentStepIndex]);

  const sectionTabsForHu = useMemo(
    () =>
      availableTabs.map(value => ({
        value,
        label: t(reviewSectionTitleTranslationKey[value]),
      })),
    [availableTabs, t],
  );

  const stepperSteps = useMemo(
    () =>
      availableTabs.map((tab, index) => ({
        id: tab,
        title: t(reviewSectionTitleTranslationKey[tab]),
        number: index + 1,
      })),
    [availableTabs, t],
  );

  const activeSectionType = availableTabs[currentStepIndex] ?? availableTabs[0];
  const isLastStep =
    availableTabs.length <= 1 || currentStepIndex === availableTabs.length - 1;
  const isFirstStep = currentStepIndex === 0;

  const currentStepQuestions = useMemo(() => {
    switch (activeSectionType) {
      case ReviewInputSectionType.FORM:
        return formQuestions;
      case ReviewInputSectionType.GOAL:
        return goalQuestions;
      case ReviewInputSectionType.COMPETENCY:
        return competencyQuestions;
      default:
        return [];
    }
  }, [activeSectionType, formQuestions, goalQuestions, competencyQuestions]);

  const {
    isActive: showCalibrationComparison,
    getHeaderActions,
    drawerProps: calibrationDrawerProps,
  } = useReviewCalibrationComparison(review);

  const reasonOptions = Array.from({ length: 4 }, (_, i) => ({
    value: i + 1,
    label: t(getReasonTranslationKey(i)),
  }));

  const { closeDialog } = useDialogLayer();
  const { closeDrawer } = useDrawerLayer();

  const finishReviewModalId = useId();
  const closeFinishReviewModal = () => closeDialog(finishReviewModalId);
  const { openDialog: showFinishReviewModal } = useDialogLayerItem(
    finishReviewModalId,
    {
      title: t('form.finish_review_modal.review_title'),
      textBody: t(
        getFinishReviewModalDescriptionKey(
          review?.type,
          canBeShared,
          canBeSharedBeforeCycleFinish,
        ),
      ),
      primaryButtonProps: {
        children: t('form.finish_review_modal.confirm_button'),
        loading: isSubmitting,
        disabled: isSubmitting,
        onClick: () => {
          closeFinishReviewModal();
          handleSubmit(submit)();
        },
      },
      secondaryButtonProps: {
        children: t('general:CANCEL'),
        disabled: isSubmitting,
        onClick: closeFinishReviewModal,
      },
      dialogProps: { fullWidth: true, maxWidth: 'sm' },
    },
  );

  const shareReviewModalId = useId();
  const closeShareReviewModal = () => closeDialog(shareReviewModalId);
  const { openDialog: showShareReviewModal } = useDialogLayerItem(
    shareReviewModalId,
    {
      title: t('form.share_modal.title', { name: firstName }),
      textBody: t('form.share_modal.description', { name: firstName }),
      primaryButtonProps: {
        children: t('form.share_modal.accept'),
        loading: isSharingReview,
        disabled: isSharingReview,
        onClick: () => {
          if (!review?.reviewedId) return;
          closeShareReviewModal();
          shareReviewMutate();
        },
      },
      secondaryButtonProps: {
        children: t('general:CANCEL'),
        disabled: isSharingReview,
        onClick: closeShareReviewModal,
      },
      dialogProps: { fullWidth: true, maxWidth: 'xs' },
    },
  );

  const requestEditionDrawerId = useId();
  const closeAndResetRequestEditionDrawer = () => {
    closeDrawer(requestEditionDrawerId);
    setSelectedReason(null);
  };
  const { openDrawer: showRequestEditionDrawer } = useDrawerLayerItem(
    requestEditionDrawerId,
    {
      title: t('form.request_edit.title'),
      onClose: closeAndResetRequestEditionDrawer,
      children: (
        <RequestEditionDrawerContent
          description={t('form.request_edit.description')}
          reasonTitle={t('form.request_edit.add_reason')}
          options={reasonOptions}
          selectedReason={selectedReason}
          onReasonChange={setSelectedReason}
        />
      ),
      primaryButtonProps: {
        children: t('form.request_edit.cta'),
        loading: isRequestingEdition,
        disabled: isRequestingEdition,
        onClick: () => {
          closeAndResetRequestEditionDrawer();
          requestEditionMutate();
        },
      },
      secondaryButtonProps: {
        children: t('general:CANCEL'),
        disabled: isRequestingEdition,
        onClick: closeAndResetRequestEditionDrawer,
      },
    },
  );

  if (!id) return null;

  if (reviewLoading) {
    return null;
  }

  return (
    <>
      <FormProvider {...form}>
        <Stack
          sx={{
            gap: 3,
            width: '100%',
            boxSizing: 'border-box',
          }}
        >
          {requestedEdition && (
            <HuAlert
              severity="warning"
              title={t('form.request_edit.pending')}
              description={t('form.request_edit.pending_description')}
            />
          )}
          {isFinished && review ? (
            <CompletedReviewCard
              reviewed={reviewed}
              score={review.score}
              scoreTag={review.scoreTag}
              answeredAt={effectiveForm?.answeredAt ?? undefined}
              summary={summary}
              withSummary={Boolean(withSummary)}
              shareStatus={shareStatus || DeliveryStatus.NOT_SHARED}
              showSharedMessage={showSharedMessage}
              canRequestEdition={canRequestEdition}
              onRequestEdition={() => showRequestEditionDrawer()}
            />
          ) : (
            <Stack
              sx={{
                flexDirection: 'row',
                alignItems: 'center',
                justifyContent: 'space-between',
                flexWrap: 'wrap',
                gap: 2,
                p: 3,
                borderRadius: '20px',
                backgroundColor: 'background.paper',
                borderColor: 'divider',
                borderWidth: 1,
                borderStyle: 'solid',
                width: '100%',
                boxSizing: 'border-box',
              }}
            >
              <Stack
                sx={{
                  flexDirection: 'row',
                  alignItems: 'center',
                  gap: 2,
                  minWidth: 0,
                }}
              >
                <HuAvatar
                  size="large"
                  src={reviewed?.profilePicture ?? undefined}
                  text={getInitials(reviewedFullName)}
                  alt=""
                  sx={{ flexShrink: 0 }}
                />
                <HuTitle
                  title={reviewedFullName}
                  variant="L"
                  sx={{ minWidth: 0 }}
                />
              </Stack>
              <Stack
                sx={{ flexDirection: 'row', alignItems: 'center', gap: 2 }}
              >
                {/** Temporally hidden share on this view */}
                {false && showShareButton && (
                  <Button
                    variant="contained"
                    onClick={() => showShareReviewModal()}
                    disabled={shareStatus !== DeliveryStatus.NOT_SHARED}
                  >
                    {t('form.share_review.share_review_with', {
                      name: firstName,
                    })}
                  </Button>
                )}
              </Stack>
            </Stack>
          )}
          {isOmitted && (
            <HuAlert
              severity="warning"
              title={t('form.cycle_finished_warning')}
              sx={{ width: '100%' }}
            />
          )}
          {description && <TemplateDescription text={description} />}
          {availableTabs.length > 0 && (
            <Stack sx={{ gap: 2, width: '100%' }}>
              {availableTabs.length > 1 &&
                (isFormDisabled ? (
                  <HuTabs
                    value={activeSectionType}
                    tabs={sectionTabsForHu}
                    onTabChange={v => {
                      const idx = availableTabs.indexOf(
                        v as ReviewInputSectionType,
                      );
                      if (idx >= 0) setCurrentStepIndex(idx);
                    }}
                  />
                ) : (
                  <HuStepper
                    steps={stepperSteps}
                    currentStep={currentStepIndex}
                  />
                ))}
              {activeSectionType === ReviewInputSectionType.FORM &&
                formQuestions.length > 0 && (
                  <ReviewInputSection
                    reviewItems={formQuestions}
                    type={ReviewInputSectionType.FORM}
                    answered={isFormDisabled}
                    getHeaderActions={getHeaderActions}
                  />
                )}
              {activeSectionType === ReviewInputSectionType.GOAL &&
                goalQuestions.length > 0 && (
                  <ReviewInputSection
                    canViewGoalDetails={canViewGoalDetails}
                    reviewItems={goalQuestions}
                    type={ReviewInputSectionType.GOAL}
                    answered={isFormDisabled}
                    getHeaderActions={getHeaderActions}
                  />
                )}
              {activeSectionType === ReviewInputSectionType.COMPETENCY &&
                competencyQuestions.length > 0 && (
                  <ReviewInputSection
                    reviewItems={competencyQuestions}
                    type={ReviewInputSectionType.COMPETENCY}
                    answered={isFormDisabled}
                    getHeaderActions={getHeaderActions}
                  />
                )}
            </Stack>
          )}
          {!isFormDisabled && (
            <Stack
              sx={{
                width: '100%',
                gap: 2,
                alignItems: 'flex-end',
              }}
            >
              {currentStepQuestions.some(item => item.required) && (
                <Typography
                  variant="body2"
                  sx={{ alignSelf: 'stretch', textAlign: 'left' }}
                >
                  <Typography component="span">{'* '}</Typography>
                  {t('form.required_answer')}
                </Typography>
              )}
              <Stack sx={{ flexDirection: 'row', gap: 2 }}>
                {!isFirstStep && (
                  <Button
                    onClick={() => setCurrentStepIndex(prev => prev - 1)}
                    variant="tertiary"
                    size="large"
                    startIcon={<IconArrowLeft />}
                  >
                    {t('general:back')}
                  </Button>
                )}
                {isLastStep ? (
                  <Button
                    onClick={() => showFinishReviewModal()}
                    disabled={!canSubmit}
                    variant="contained"
                    color="primary"
                    size="large"
                  >
                    {t(
                      `form.review.finish_${isSelfReview ? 'auto_review' : 'review'}`,
                      {
                        name: reviewedFullName,
                      },
                    )}
                  </Button>
                ) : (
                  <ReviewNextStepButton
                    currentStepQuestions={currentStepQuestions}
                    onClick={() => setCurrentStepIndex(prev => prev + 1)}
                    label={t('general:next')}
                  />
                )}
              </Stack>
            </Stack>
          )}
        </Stack>
      </FormProvider>
      {showCalibrationComparison && (
        <CalibrationComparisonDrawer {...calibrationDrawerProps} />
      )}
    </>
  );
};

export default ReviewForm;
