import { type FC, useEffect, useState } from 'react';
import { useInfiniteQuery, useQuery, useQueryClient } from 'react-query';

import {
  IconClipboard,
  IconClipboardCheck,
  IconClipboardX,
  IconInfoCircle,
  type TablerIcon,
} from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import HuAccordion from '@material-hu/components/design-system/Accordion';
import HuCardContainer from '@material-hu/components/design-system/CardContainer';
import StateCard from '@material-hu/components/design-system/StateCard';
import HuTitle from '@material-hu/components/design-system/Title';
import HuTooltip from '@material-hu/components/design-system/Tooltip';

import { useAuth } from 'src/contexts/JWTContext';
import {
  getApprovalGroup,
  getApprovalGroups,
  getTransitionsStates,
} from 'src/pages/dashboard/serviceManagement/services';
import {
  type ApprovalGroup,
  type ApprovalGroupTask,
  ApprovalScreenSource,
  ApprovalStateName,
  type Task,
} from 'src/pages/dashboard/serviceManagement/types';
import {
  calculateGroupApprovalStatus,
  getApprovalPillDescription,
  getApprovalPolicy,
  getApprovalStateName,
} from 'src/pages/dashboard/serviceManagement/utils';
import { formatLocalizedDate } from 'src/utils/date';
import { type LokaliseTFunction, useLokaliseTranslation } from 'src/utils/i18n';

import { InfiniteList } from 'src/components/list';

import { serviceManagementKeys } from '../../../queries';
import { getUserDisplayName } from '../../../utils';
import { ApprovalActions } from '../../serviceItems/components/ApprovalActions';

import ApprovalsAvatar from './ApprovalsAvatar';
import ApprovalGroupSkeleton from './Skeletons/ApprovalGroupSkeleton';

type RequestTabProps = {
  taskData: Task;
  defaultApproval?: string;
};

const approvalGroupProps = (
  type: ApprovalStateName,
  t: LokaliseTFunction,
): {
  icon: TablerIcon;
  color: 'success' | 'error' | 'highlight' | undefined;
  label: string;
} => {
  switch (type) {
    case ApprovalStateName.APPROVED:
      return {
        icon: IconClipboardCheck,
        color: 'success',
        label: t('approvals.approved'),
      };
    case ApprovalStateName.REJECTED:
      return {
        icon: IconClipboardX,
        color: 'error',
        label: t('approvals.rejected'),
      };
    case ApprovalStateName.PENDING:
      return {
        icon: IconClipboard,
        color: 'highlight',
        label: t('approvals.requested'),
      };
    case ApprovalStateName.CANCELLED:
      return {
        icon: IconClipboardX,
        color: undefined,
        label: t('approvals.cancelled'),
      };
  }
};

const ApprovalsTab: FC<RequestTabProps> = ({
  taskData,
  defaultApproval = null,
}) => {
  const { t } = useLokaliseTranslation('service_management');
  const { user } = useAuth();
  const queryClient = useQueryClient();
  const params: Omit<{ page: number; limit: number }, 'page'> = {
    limit: 10,
  };

  const {
    data,
    isLoading,
    isError,
    isSuccess,
    refetch,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery(
    serviceManagementKeys.approvalGroups.list(taskData?.id, params),
    ({ pageParam = 1 }) =>
      getApprovalGroups(taskData?.id, { ...params, page: pageParam }),
    {
      getNextPageParam: lastPage => {
        const { page, totalPages } = lastPage.data;
        return page < totalPages ? page + 1 : undefined;
      },
      select: response => ({
        ...response,
        pages: response.pages.map(page => page.data),
      }),
      onError: () => {
        // Prevent global error handler
      },
      enabled: !!taskData?.id,
      keepPreviousData: false,
    },
  );

  const [approvalGroups, setApprovalGroups] = useState(
    data?.pages?.flatMap(page => page.items) || [],
  );

  useEffect(() => {
    const newGroups = data?.pages?.flatMap(page => page.items) || [];
    setApprovalGroups(newGroups);
  }, [data]);

  const updateTaskStateInCache = async (approvalGroupId?: string) => {
    if (!approvalGroupId) return;

    try {
      // Fetch only the updated tasks for this specific group
      const updatedTasks = await queryClient.fetchQuery(
        serviceManagementKeys.approvalGroups.group(
          taskData.id,
          approvalGroupId,
        ),
        () => getApprovalGroup(taskData.id, approvalGroupId),
        { staleTime: 0 },
      );

      setApprovalGroups(currentGroups =>
        currentGroups.map(group => {
          if (group.id === approvalGroupId) {
            return {
              ...group,
              tasks: updatedTasks.data.items,
              status: calculateGroupApprovalStatus(
                updatedTasks.data.items,
                group.approvalPolicy.policyType,
              ),
            };
          }
          return group;
        }),
      );
    } catch (error) {
      refetch();
    }
  };

  // Find first task on pending status
  const transitionTask = approvalGroups
    ?.flatMap(group => group.tasks)
    .find(
      task =>
        getApprovalStateName(task.state.name) === ApprovalStateName.PENDING,
    );

  const { data: states } = useQuery(
    serviceManagementKeys.states.list(transitionTask?.state.id!),
    () => getTransitionsStates(transitionTask?.state.id!),
    {
      enabled: !!transitionTask,
      select: response => response.data,
    },
  );

  const approvalToTask = (
    task: ApprovalGroupTask,
    approvalGroup: ApprovalGroup,
  ) => {
    return {
      ...task,
      name: approvalGroup.name,
      id: task.taskId,
      catalogItem: taskData.catalogItem,
    };
  };

  const needApproval = (task: ApprovalGroupTask) =>
    getApprovalStateName(task.state.name) === ApprovalStateName.PENDING &&
    task.assignee?.id === user?.id;

  return (
    <Stack
      sx={{
        width: '100%',
        height: '100%',
        overflow: 'auto',
        p: 3,
        gap: 2,
        backgroundColor: ({ palette }) => palette.new.background.layout.default,
      }}
    >
      <Stack>
        <Typography
          variant="globalM"
          fontWeight="fontWeightSemiBold"
        >
          {t('approvals.steps')}
        </Typography>
      </Stack>
      <InfiniteList
        isLoading={isLoading}
        isSuccess={isSuccess}
        isEmpty={isSuccess && !approvalGroups.length}
        fetchNextPage={fetchNextPage}
        hasNextPage={hasNextPage}
        isFetchingNextPage={isFetchingNextPage}
        loadingSkeleton
        noResultsLabel={
          <StateCard
            variant="primary"
            title={t('approvals.empty.title')}
            description={t('approvals.empty.description')}
          />
        }
        renderSkeleton={<ApprovalGroupSkeleton />}
      >
        {approvalGroups.map(approvalGroup => {
          const { icon, color, label } = approvalGroupProps(
            approvalGroup.status,
            t,
          );

          const defaultExpanded = approvalGroup.tasks.some(
            task => task.taskId === defaultApproval,
          );

          const sortedTasks = approvalGroup.tasks.sort(
            (a, b) => Number(needApproval(b)) - Number(needApproval(a)),
          );

          return (
            <HuCardContainer
              key={approvalGroup.id}
              fullWidth
              padding={0}
              sx={{ mb: 2 }}
            >
              <HuAccordion
                title={approvalGroup.name}
                defaultExpanded={defaultExpanded}
                description={t(
                  getApprovalPolicy(
                    approvalGroup.status,
                    approvalGroup.approvalPolicy.policyType,
                  ),
                )}
                elevation={0}
                avatar={{ Icon: icon, color: color }}
                pill={{
                  label: label,
                  hasIcon: false,
                  type: color || 'disabled',
                }}
                customDetail={
                  <Stack sx={{ p: 1, px: 0, gap: 1 }}>
                    {sortedTasks.map(task => (
                      <Stack
                        key={task.taskId}
                        sx={{
                          p: 2,
                          borderRadius: 2,
                          backgroundColor: ({ palette }) =>
                            palette.new.background.layout.default,
                          flexDirection: 'row',
                          alignItems: 'center',
                          justifyContent: 'space-between',
                        }}
                      >
                        <Stack
                          sx={{
                            flexDirection: 'row',
                            gap: 1.5,
                          }}
                        >
                          <Stack>
                            <ApprovalsAvatar task={task} />
                          </Stack>
                          <HuTitle
                            title={
                              <Stack
                                sx={{
                                  flexDirection: 'row',
                                  alignItems: 'center',
                                  gap: 1,
                                }}
                              >
                                {getUserDisplayName(task.assignee!, user!, t)}
                                {getApprovalStateName(task.state.name) ===
                                  ApprovalStateName.CANCELLED && (
                                  <HuTooltip
                                    direction="bottom"
                                    title={t('approvals.not_required.title')}
                                    description={t(
                                      'approvals.not_required.description',
                                    )}
                                  >
                                    <IconInfoCircle size={14} />
                                  </HuTooltip>
                                )}
                              </Stack>
                            }
                            copetin={getApprovalPillDescription(
                              task.state,
                              null,
                              formatLocalizedDate(
                                task.completedAt || task.updatedAt,
                                {
                                  includeTime: true,
                                },
                              ) || '-',
                              t,
                            )}
                            description={task.message}
                            variant="S"
                          />
                        </Stack>
                        <Stack>
                          {needApproval(task) && (
                            <ApprovalActions
                              task={approvalToTask(task, approvalGroup)}
                              states={states || []}
                              invalidateQueries={() =>
                                updateTaskStateInCache(approvalGroup.id)
                              }
                              screenSource={ApprovalScreenSource.APPROVALS_TAB}
                            />
                          )}
                        </Stack>
                      </Stack>
                    ))}
                  </Stack>
                }
              />
            </HuCardContainer>
          );
        })}
      </InfiniteList>
    </Stack>
  );
};

export default ApprovalsTab;
