import { type ReactNode, useCallback, useMemo, useRef, useState } from 'react';

import { useDrawerV2 } from '@material-hu/hooks/useDrawerV2';
import { IconBan, IconCheck, IconX } from '@material-hu/icons/tabler';

import Alert from '@material-hu/components/design-system/Alert';
import Button from '@material-hu/components/design-system/Buttons/Button';
import useHuSnackbar from '@material-hu/components/design-system/Snackbar';
import { useDrawerLayer } from '@material-hu/components/layers/Drawers';

import { useAuth } from 'src/contexts/JWTContext';
import {
  useGetCategorizedHour,
  useOverrideCategorizedHourStatus,
  useReviewCategorizedHourApprovalStep,
} from 'src/hooks/queryHooks/timeTracking';
import usePermissions from 'src/hooks/usePermissions';
import {
  type ApprovableStatus,
  type CategorizedHourApprovalStep,
  CategorizedHourApprovalStepState,
  TimeTrackingCategorizedHourStatus,
} from 'src/types/timeTracking';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { UserPermissions } from 'src/utils/permissions';

import {
  checkEditAction,
  getActionableStep,
  getApprovalStepForResolutionEdit,
  getLastReviewedStep,
  getStepApproverId,
  mapToApproverStepItems,
} from '../utils';

import ApprovalDetailDrawer from './ApprovalDetailDrawer';
import RevokeRequestDrawer from './RevokeRequestDrawer';
import { useSupersededApprovalStepAlert } from './useSupersededApprovalStepAlert';

type DrawerProps = {
  categorizedHourId: string;
};

type UseApprovalDetailDrawerParams = {
  /** Called after a successful review; `wasLastPending` is computed before mutate (see `getWasLastPendingResolution`). */
  onResolveSuccess?: (wasLastPending: boolean) => void;
  /** Snapshot list context when the drawer starts a review mutation (not on success). */
  getWasLastPendingResolution?: (categorizedHourId: string) => boolean;
};

// When a "global approve" action is added (admin approves bypassing steps, similar to revoke),
// extract action routing + mutations into a dedicated useApprovalActions hook.
export const useApprovalDetailDrawer = ({
  onResolveSuccess,
  getWasLastPendingResolution,
}: UseApprovalDetailDrawerParams = {}) => {
  const { t } = useLokaliseTranslation([
    'time_tracker',
    'approval_requests',
    'general',
  ]);
  const { enqueueSnackbar } = useHuSnackbar();
  const [isEditing, setIsEditing] = useState(false);
  const [responseText, setResponseText] = useState('');
  const [currentCategorizedHourId, setCurrentCategorizedHourId] = useState<
    string | null
  >(null);

  const { categorizedHour, isLoading } = useGetCategorizedHour(
    currentCategorizedHourId,
  );
  const reviewMutation = useReviewCategorizedHourApprovalStep();
  const overrideMutation = useOverrideCategorizedHourStatus();
  const { openDrawer: openRevokeDrawer } = useDrawerLayer();
  const closeApprovalDetailDrawerRef = useRef<(() => void) | null>(null);
  const { hasAny: canManageTimeTracking } = usePermissions([
    UserPermissions.MANAGE_TIME_TRACKING,
  ]);
  const { user } = useAuth();

  const approvalSteps = categorizedHour?.approvalSteps;
  const hasApprovalSteps = approvalSteps != null && approvalSteps.length > 0;
  const actionableStep = hasApprovalSteps
    ? getActionableStep(approvalSteps)
    : undefined;
  const lastReviewedStep = hasApprovalSteps
    ? getLastReviewedStep(approvalSteps)
    : undefined;
  const canEditResponse =
    canManageTimeTracking || user?.id === getStepApproverId(lastReviewedStep);
  const isApprovedByLoggedUser =
    approvalSteps?.some(
      step =>
        step.state === CategorizedHourApprovalStepState.APPROVED &&
        (step.approver?.id === user?.id || step.approverId === user?.id),
    ) ?? false;
  const isCurrentUserInApprovers = actionableStep?.potentialApprovers?.some(
    approver => approver.id === user?.id,
  );
  const isRevoked =
    categorizedHour?.status === TimeTrackingCategorizedHourStatus.REJECTED &&
    categorizedHour?.statusOverride != null;
  const canRevoke =
    canManageTimeTracking &&
    (categorizedHour?.status === TimeTrackingCategorizedHourStatus.APPROVED ||
      categorizedHour?.status ===
        TimeTrackingCategorizedHourStatus.AUTO_APPROVED) &&
    !isLoading;
  const showResolveAsAdminAlert =
    canManageTimeTracking &&
    categorizedHour?.status === TimeTrackingCategorizedHourStatus.PENDING &&
    !isCurrentUserInApprovers &&
    !isLoading;
  const {
    showSupersededByOtherApprover,
    supersededStepPosition,
    reset: resetSupersededAlert,
  } = useSupersededApprovalStepAlert({
    categorizedHourId: currentCategorizedHourId,
    categorizedHour,
    isLoading,
    actionableStep,
    lastReviewedStep,
    isCurrentUserInApprovers,
    canManageTimeTracking,
    isReviewMutationLoading: reviewMutation.isLoading,
  });

  const approverStepItems = useMemo(
    () =>
      hasApprovalSteps ? mapToApproverStepItems(approvalSteps, t) : undefined,
    [hasApprovalSteps, approvalSteps, t],
  );

  const handleEditResponse = useCallback(() => {
    setIsEditing(true);
    setResponseText(categorizedHour?.note || '');
  }, [categorizedHour?.note]);

  const handleCancelEdit = useCallback(() => {
    setIsEditing(false);
    setResponseText('');
  }, []);

  const handleResponseTextChange = useCallback((value: string) => {
    setResponseText(value);
  }, []);

  const handleDrawerClose = useCallback(
    (closeDrawer: () => void) => {
      setIsEditing(false);
      setResponseText('');
      resetSupersededAlert();
      setCurrentCategorizedHourId(null);
      closeDrawer();
    },
    [resetSupersededAlert],
  );

  const handleReviewStep = useCallback(
    (status: ApprovableStatus, stepOverride?: CategorizedHourApprovalStep) => {
      const stepToReview = stepOverride ?? actionableStep;
      if (!currentCategorizedHourId || !stepToReview) {
        return;
      }
      const rawStepId = stepToReview.id;
      const approvalStepId =
        typeof rawStepId === 'number' ? rawStepId : String(rawStepId).trim();
      if (
        approvalStepId === '' ||
        (typeof approvalStepId === 'number' && Number.isNaN(approvalStepId))
      ) {
        return;
      }

      const wasLastPending =
        getWasLastPendingResolution?.(currentCategorizedHourId) ?? false;

      reviewMutation.mutate(
        {
          categorizedHourId: currentCategorizedHourId,
          approvalStepId,
          state: status,
          comment: responseText || undefined,
        },
        {
          onSuccess: () => {
            setIsEditing(false);
            setResponseText('');
            enqueueSnackbar({
              title: t('approval_requests:feedback.request_modified'),
              variant: 'success',
            });
            onResolveSuccess?.(wasLastPending);
            if (closeApprovalDetailDrawerRef.current) {
              handleDrawerClose(closeApprovalDetailDrawerRef.current);
            }
          },
        },
      );
    },
    [
      currentCategorizedHourId,
      actionableStep,
      responseText,
      reviewMutation,
      enqueueSnackbar,
      handleDrawerClose,
      getWasLastPendingResolution,
      onResolveSuccess,
      t,
    ],
  );

  const handleChangeRevokedToApproved = useCallback(() => {
    if (!currentCategorizedHourId) return;
    const wasLastPending =
      getWasLastPendingResolution?.(currentCategorizedHourId) ?? false;
    overrideMutation.mutate(
      {
        id: currentCategorizedHourId,
        status: TimeTrackingCategorizedHourStatus.APPROVED,
        comment: responseText || undefined,
      },
      {
        onSuccess: () => {
          setIsEditing(false);
          setResponseText('');
          enqueueSnackbar({
            title: t('approval_requests:feedback.request_modified'),
            variant: 'success',
          });
          onResolveSuccess?.(wasLastPending);
          if (closeApprovalDetailDrawerRef.current) {
            handleDrawerClose(closeApprovalDetailDrawerRef.current);
          }
        },
      },
    );
  }, [
    currentCategorizedHourId,
    responseText,
    overrideMutation,
    enqueueSnackbar,
    handleDrawerClose,
    getWasLastPendingResolution,
    onResolveSuccess,
    t,
  ]);

  const isReviewLoading =
    reviewMutation.isLoading || overrideMutation.isLoading;

  const handleRevokeClick = useCallback(() => {
    if (!currentCategorizedHourId) return;
    const id = currentCategorizedHourId;
    openRevokeDrawer({
      content: (
        <RevokeRequestDrawer
          categorizedHourId={id}
          onSuccess={() => {
            onResolveSuccess?.(false);
            if (closeApprovalDetailDrawerRef.current) {
              handleDrawerClose(closeApprovalDetailDrawerRef.current);
            }
          }}
        />
      ),
    });
  }, [
    currentCategorizedHourId,
    openRevokeDrawer,
    onResolveSuccess,
    handleDrawerClose,
  ]);

  const {
    showDrawer: showApprovalDetailDrawer,
    drawer,
    closeDrawer: closeApprovalDetailDrawer,
  } = useDrawerV2<DrawerProps>(({ closeDrawer }) => {
    const isPending =
      categorizedHour?.status === TimeTrackingCategorizedHourStatus.PENDING;
    const canReviewCurrentStep = hasApprovalSteps && actionableStep != null;
    const stepForResolutionEdit = getApprovalStepForResolutionEdit(
      approvalSteps,
      categorizedHour?.status ?? TimeTrackingCategorizedHourStatus.PENDING,
    );
    const stepForResolutionEditWasApproved =
      stepForResolutionEdit?.state ===
      CategorizedHourApprovalStepState.APPROVED;
    const canShowPendingResolveActions =
      canManageTimeTracking || !!isCurrentUserInApprovers;

    const handleApprove = () => {
      handleReviewStep(TimeTrackingCategorizedHourStatus.APPROVED);
    };

    const handleReject = () => {
      handleReviewStep(TimeTrackingCategorizedHourStatus.REJECTED);
    };

    const editAction = checkEditAction(
      isRevoked,
      stepForResolutionEditWasApproved,
    );

    let footer: ReactNode;
    if (canRevoke && !isEditing) {
      footer = (
        <Button
          variant="error"
          startIcon={<IconBan size={16} />}
          onClick={handleRevokeClick}
          fullWidth
        >
          {t('approval_requests:revoke_request')}
        </Button>
      );
    } else if (showResolveAsAdminAlert) {
      footer = (
        <Alert
          severity="info"
          title={t('approval_requests:resolve_request_as_admin')}
          description={t(
            'approval_requests:resolve_request_as_admin_description',
          )}
          hasClose
        />
      );
    }

    const showResolveActions =
      isPending && !isEditing && canShowPendingResolveActions;

    return {
      children: (
        <ApprovalDetailDrawer
          categorizedHour={categorizedHour || undefined}
          isLoading={isLoading}
          isEditing={isEditing}
          responseText={responseText}
          onEditResponse={handleEditResponse}
          onCancelEdit={handleCancelEdit}
          onResponseTextChange={handleResponseTextChange}
          approverSteps={approverStepItems}
          canEditResponse={canEditResponse}
          hasLastReviewedStep={lastReviewedStep != null}
          isCurrentStepApprover={!!isCurrentUserInApprovers}
          isApprovedByLoggedUser={isApprovedByLoggedUser}
          showSupersededByOtherApprover={showSupersededByOtherApprover}
          supersededStepPosition={supersededStepPosition}
        />
      ),
      title: t('approvals.detail_title'),
      onClose: () => handleDrawerClose(closeDrawer),
      footer,
      ...(showResolveActions && {
        primaryButtonProps: {
          children: t('approval_requests:approve'),
          startIcon: <IconCheck size={16} />,
          onClick: handleApprove,
          fullWidth: true,
          loading: isReviewLoading,
          disabled: !canReviewCurrentStep,
        },
        secondaryButtonProps: {
          children: t('approval_requests:reject'),
          startIcon: <IconX size={16} />,
          onClick: handleReject,
          fullWidth: true,
          loading: isReviewLoading,
          disabled: !canReviewCurrentStep,
        },
      }),
      ...(isEditing &&
        (isRevoked || stepForResolutionEdit != null) && {
          primaryButtonProps: {
            children: t(editAction.label),
            startIcon: editAction.icon,
            onClick: () =>
              isRevoked
                ? handleChangeRevokedToApproved()
                : handleReviewStep(editAction.status, stepForResolutionEdit!),
            fullWidth: true,
            loading: isReviewLoading,
          },
          secondaryButtonProps: {
            children: t('time_tracker:exit_without_saving'),
            onClick: handleCancelEdit,
            fullWidth: true,
          },
        }),
    };
  });

  closeApprovalDetailDrawerRef.current = closeApprovalDetailDrawer;

  const memoizedShowDrawer = useCallback(
    (id: string) => {
      resetSupersededAlert();
      setCurrentCategorizedHourId(id);
      showApprovalDetailDrawer({ categorizedHourId: id });
    },
    [resetSupersededAlert, showApprovalDetailDrawer],
  );

  return {
    drawer,
    showApprovalDetailDrawer: memoizedShowDrawer,
    closeApprovalDetailDrawer,
  };
};
