import { type AxiosResponse } from 'axios';
import { isNil } from 'lodash-es';

import { queryClient } from 'src/config/react-query';
import {
  type DateToRequest,
  type PolicyTypes,
  type PolicyTypesResponse,
  Role,
  type SectionsManager,
  type VacationsFilterValues,
} from 'src/types/vacations';

export const vacationsKeys = {
  all: () => ['vacations'],
  usersList: (
    search: string,
    type: SectionsManager,
    isManagerView?: boolean,
  ) => [...vacationsKeys.all(), { search, type, isManagerView }],
  policyTypes: {
    all: () => [...vacationsKeys.all(), 'policyTypes'],
    list: () => [...vacationsKeys.policyTypes.all(), 'list'],
    listByUserId: (id: number | string) => [
      ...vacationsKeys.policyTypes.all(),
      Number(id),
    ],
    detail: (policyTypeId: number | string, userId: number | string | null) => [
      ...vacationsKeys.policyTypes.list(),
      Number(userId),
      Number(policyTypeId),
    ],
    balance: (
      policyTypeId: number | string,
      userId: number | string | null,
    ) => [...vacationsKeys.policyTypes.detail(policyTypeId, userId), 'balance'],
    futureBalance: (
      policyTypeId: number | string,
      userId: number | string | null,
    ) => [...vacationsKeys.policyTypes.balance(policyTypeId, userId), 'future'],
    conformation: (
      policyTypeId: number | string,
      userId: number | string | null,
      onlyPositiveBalance?: boolean,
    ) => [
      ...vacationsKeys.policyTypes.balance(policyTypeId, userId),
      'conformation',
      onlyPositiveBalance,
    ],
    requestedDaysAmount: (
      policyTypeId: number | string,
      issuerId: number | null,
      fromDate: DateToRequest | undefined,
      toDate: DateToRequest | undefined,
      amountInMoney?: number,
    ) => [
      ...vacationsKeys.policyTypes.detail(policyTypeId, issuerId),
      fromDate,
      toDate,
      amountInMoney,
      'requestedDaysAmount',
    ],
  },
  collaborator: {
    all: () => [...vacationsKeys.all(), 'collaborator'],
    requestsReport: {
      all: () => [...vacationsKeys.collaborator.all(), 'requestsReport'],
      filters: (policyTypeId: string | number) => [
        ...vacationsKeys.collaborator.requestsReport.all(),
        Number(policyTypeId),
      ],
    },
  },
  manager: {
    all: () => [...vacationsKeys.all(), 'manager'],
    requestCalendar: {
      all: () => [...vacationsKeys.manager.all(), 'requestCalendar'],
      filters: (
        month: Date,
        filter: VacationsFilterValues,
        isManagerView?: boolean,
      ) => [
        ...vacationsKeys.manager.requestCalendar.all(),
        month.toString(),
        filter,
        isManagerView,
      ],
    },
    requestsReport: {
      all: () => [...vacationsKeys.manager.all(), 'requestsReport'],
      filters: (filter?: VacationsFilterValues) => [
        ...vacationsKeys.manager.requestsReport.all(),
        filter,
      ],
    },
    balanceReport: {
      all: () => [...vacationsKeys.manager.all(), 'balanceReport'],
      filters: (filter: VacationsFilterValues) => [
        ...vacationsKeys.manager.balanceReport.all(),
        filter,
      ],
    },
  },
  policies: (policyTypes: number[]) => [
    ...vacationsKeys.all(),
    'policies',
    policyTypes,
  ],
  detail: (id: string | number) => [
    ...vacationsKeys.all(),
    'detail',
    Number(id),
  ],
  approvers: (vacationId: string | number, stepId: string | number) => [
    ...vacationsKeys.detail(vacationId),
    'step',
    Number(stepId),
    'approvers',
  ],
  steps: (id: string | number) => [...vacationsKeys.detail(id), 'steps'],
  notifications: {
    all: () => [...vacationsKeys.all(), 'notifications'],
    module: () => [...vacationsKeys.notifications.all(), 'module'],
  },
  holidays: {
    byDateRange: (userId: number, fromDate: string, toDate: string) =>
      [
        ...vacationsKeys.all(),
        'holidaysByDate',
        userId,
        fromDate,
        toDate,
      ] as const,
  },
  segmentation: () => [...vacationsKeys.all(), 'segmentation'],
};

export const updateBalanceReport = () => {
  queryClient.invalidateQueries(vacationsKeys.manager.balanceReport.all());
};

export const updateRequestsCollaborator = () => {
  queryClient.invalidateQueries(
    vacationsKeys.collaborator.requestsReport.all(),
  );
};

export const updateRequestsManager = () => {
  queryClient.invalidateQueries(vacationsKeys.manager.requestsReport.all());
};

export const updateVacations = (id: string | number) => {
  queryClient.invalidateQueries(vacationsKeys.detail(id));
};

export const getListPolicyTypes = (userId: string | number) =>
  queryClient.getQueryData<AxiosResponse<PolicyTypesResponse>>(
    vacationsKeys.policyTypes.listByUserId(userId),
  );

export const getPolicyTypeById = (id: number, userId: number) => {
  const response = getListPolicyTypes(userId);
  return response?.data?.find((elem: PolicyTypes) => elem.id === id);
};

export const resolveSelectedPolicyType = (
  policyTypeId: number | undefined,
  userId: number,
  policyTypesFromDrawer: PolicyTypes[],
) => {
  if (isNil(policyTypeId)) {
    return undefined;
  }

  const policyTypeFromCache = getPolicyTypeById(policyTypeId, userId);
  if (policyTypeFromCache) {
    return policyTypeFromCache;
  }

  return policyTypesFromDrawer.find(p => p.id === policyTypeId);
};

export const updateNotifications = (role: Role) => {
  queryClient.setQueryData(
    vacationsKeys.notifications.module(),
    (oldData: any): any => {
      if (!oldData) return oldData;
      if (role === Role.MANAGER) {
        oldData.vacationRequestsAsManagerNotifications = 0;
      } else {
        oldData.vacationRequestsAsCollaboratorNotifications = 0;
      }

      return oldData;
    },
  );
};

export const updateRedBubblesManager = () => {
  queryClient.setQueryData(
    vacationsKeys.notifications.module(),
    (oldData: any): any => {
      if (!oldData) return oldData;
      oldData.vacationRequestsAsManagerNotifications =
        oldData.vacationRequestsAsManagerNotifications - 1;
      return oldData;
    },
  );
};

export const updateAllRequestInCalendar = () => {
  queryClient.invalidateQueries(vacationsKeys.manager.requestCalendar.all());
};

export const restoreMonthWithFirstPage = (
  month: Date,
  filters: VacationsFilterValues,
) => {
  queryClient.setQueryData(
    vacationsKeys.manager.requestCalendar.filters(month, filters),
    (oldData: any): any => {
      if (!oldData) return oldData;
      return {
        pages: oldData.pages.slice(0, 1),
        pageParams: oldData.pageParams.slice(0, 1),
      };
    },
  );
};
