import { formatISO } from 'date-fns';
import { pickBy } from 'lodash-es';

import api from 'src/config/api';
import { type MeResponse } from 'src/types/login';
import { type Pagination } from 'src/types/services';
import { type UserListResponse } from 'src/types/user';
import {
  type AdjustAvailableTimeParams,
  type ApprovalStepsType,
  type BalanceConfomationResponse,
  type DownloadReportBalancesResponse,
  type ExtraFieldsReport,
  type FutureBalanceResponse,
  type GetRequestToCalendarParams,
  type GetVacationsDetailParams,
  type HolidayByDate,
  type HolidaysByDateParams,
  type PoliciesResponse,
  type PolicyTypesResponse,
  type RequestTimeOff,
  type ResponseBalanceReport,
  type ResponseDetailPolicyTypes,
  type ResponseRequestCalendar,
  type ResponseRequestTimeOff,
  Role,
  type SectionsManager,
  type TimeOffAttachment,
  type TimeOffRequestedDaysResponse,
  type TimeOffRequestedDaysResponseEdit,
  VacationStatus,
  type Vacations,
  type VacationsFilterValues,
  type VacationsNotificationsResponse,
  type VacationsPaginated,
} from 'src/types/vacations';
import {
  formatSegmentationFilters,
  getResponseType,
  getVisibility,
} from 'src/utils/vacations';

const formatVacationsFilters = (filters: VacationsFilterValues) => ({
  policyTypeIds:
    filters?.policyTypeIds &&
    Object.keys(pickBy(filters.policyTypeIds)).toString(),
  policyIds:
    filters?.policyIds && Object.keys(pickBy(filters.policyIds)).toString(),
  userIds: filters?.users.map(u => u.id).toString(),
  states: filters?.states && Object.keys(pickBy(filters.states)).toString(),
  fromDate:
    filters?.fromDate &&
    formatISO(new Date(filters.fromDate), { representation: 'date' }),
  toDate:
    filters?.toDate &&
    formatISO(new Date(filters.toDate), { representation: 'date' }),
  onlyPeopleWithRequests: filters?.onlyPeopleWithRequests,
  segmentationIds: formatSegmentationFilters(filters?.segmentation).toString(),
  order: filters?.order,
  orderBy: filters?.orderBy,
  visibility: filters?.visibility && getVisibility(filters.visibility),
});

export const getHolidaysByDate = (params: HolidaysByDateParams) =>
  api.get<HolidayByDate[]>('/holidays/by-date', { params });

export const getPolicyTypesByUserId = (userId: number) =>
  api.get<PolicyTypesResponse>('/vacations/policy-types', {
    params: {
      userId,
    },
  });

export const getPolicyTypes = () =>
  api.get<PolicyTypesResponse>('/vacations/policy-types');

export const getPolicies = (policyTypes: number[]) =>
  api.get<PoliciesResponse>('/vacations/policies', {
    params: { policyTypeIds: policyTypes.toString(), page: 1, limit: 300 },
  });

export const getVacationsRequestCollaborator = (
  policyTypeId: number,
  page: number,
  limit: number,
) =>
  api.get<Pagination<Vacations>>('/vacations/requests', {
    params: {
      policyTypeId,
      role: 'COLLABORATOR',
      page,
      limit,
    },
  });

export const getVacationsRequestManager = (
  params: VacationsFilterValues,
  page: number,
  limit: number,
) =>
  api.get<Pagination<Vacations>>('/vacations/requests', {
    params: {
      ...formatVacationsFilters(params),
      role: 'MANAGER',
      page,
      limit,
    },
  });

export const createVacationRequest = (requestData: RequestTimeOff) =>
  api.post<ResponseRequestTimeOff>('/vacations/requests', requestData);

export const editFilesInRequest = ({
  id,
  attachments,
}: {
  id: number;
  attachments: TimeOffAttachment[];
}) =>
  api.put<ResponseRequestTimeOff>(`/vacations/requests/${id}/attachments`, {
    attachments,
  });

export const approveOrRejectRequest = ({
  requestId,
  stepId,
  state,
  resolutionReason,
  comment,
}: {
  requestId: number;
  stepId: number;
  state: VacationStatus;
  resolutionReason?: string;
  comment?: string;
}) =>
  api.put(`/vacations/requests/${requestId}/approval-steps/${stepId}/state`, {
    state,
    ...(resolutionReason && { resolutionReason }),
    ...(comment && { comment }),
  });

export const getVacationsDetail = (
  id: number,
  params?: GetVacationsDetailParams,
) =>
  api.get<ResponseRequestTimeOff>(`/vacations/requests/${id}`, {
    params: {
      ...params,
    },
  });

export const getPolicyTypeDetail = (
  policyTypeId: number,
  userIdCollaborator?: number,
) =>
  api.get<ResponseDetailPolicyTypes>(
    `/vacations/policy-types/${policyTypeId}`,
    {
      params: {
        userId: userIdCollaborator,
      },
    },
  );

export const getApprovalStep = (id: number) =>
  api.get<ApprovalStepsType>(`/vacations/requests/${id}/approval-steps`);

export const getApprovalStepApprovers = ({
  vacationId,
  stepId,
  page,
  limit,
  orderBy = 'NAME',
  order = 'ASC',
}: {
  vacationId: number;
  stepId: number;
  page: number;
  limit: number;
  orderBy?: string;
  order?: string;
}) =>
  api.get<UserListResponse>(
    `/vacations/requests/${vacationId}/approval-steps/${stepId}/potential-approvers`,
    {
      params: {
        page,
        limit,
        orderBy: orderBy,
        order: order,
      },
    },
  );

// Notifications
export const getVacationsNotifications = async () => {
  const [response1, response2] = await Promise.all([
    api.get<VacationsNotificationsResponse>('red-bubbles/vacations'),
    api.get<VacationsPaginated>('/vacations/requests', {
      params: {
        role: Role.MANAGER,
        states: VacationStatus.PENDING,
        limit: 1,
      },
    }),
  ]);

  const combinedData = {
    ...response1.data,
    vacationRequestsAsManagerNotifications: response2.data?.count ?? 0,
  };

  return combinedData;
};

export const clearVacationsNotifications = (body: any) =>
  api.post('red-bubbles/vacations/clear', body);

export const getBalanceReport = (
  params: VacationsFilterValues,
  page: number,
  limit: number,
  orderBy = 'NAME',
  order = 'ASC',
) =>
  api.get<ResponseBalanceReport>('vacations/balances', {
    params: {
      ...formatVacationsFilters(params),
      page,
      limit,
      orderBy,
      order,
    },
  });

export const getUserListSubordinatesForVacations = (
  userId: number,
  search: string,
  page: number,
  limit: number,
) =>
  api.get(`/organization-charts/${userId}/subordinates`, {
    params: {
      search,
      page,
      limit,
    },
  });

export const adjustAvailableTime = ({
  policyTypeId,
  userId,
  operation,
  amount,
  observations,
  cycleId,
}: AdjustAvailableTimeParams) =>
  api.post(
    `vacations/policy-types/${policyTypeId}/balances/manual-correction`,
    {
      userId,
      operation,
      amount,
      observations,
      cycleId,
    },
  );

export const getIssuerRequestsList = (
  search: string,
  page: number,
  limit: number,
  type: SectionsManager,
  visibility: Record<string, boolean>,
) =>
  api.get<UserListResponse>('/vacations/users', {
    params: {
      search: search || undefined,
      page,
      limit,
      type,
      visibility: getVisibility(visibility),
    },
  });

export const getBalanceConformationOfPolicyTypes = (
  policyTypeId: number,
  page: number,
  limit: number,
  userIdCollaborator?: number,
) =>
  api.get<BalanceConfomationResponse>(
    `vacations/policy-types/${policyTypeId}/cycles`,
    {
      params: {
        page,
        limit,
        userId: userIdCollaborator,
      },
    },
  );

export const getFutureBalance = (policyTypeId: number, userId: number) =>
  api.get<FutureBalanceResponse>(
    `vacations/policy-types/${policyTypeId}/projected-balance`,
    {
      params: {
        userId,
      },
    },
  );

export const getBalanceConformationForAdjustments = (
  policyTypeId: number,
  userCollaboratorId: number,
) =>
  api.get<BalanceConfomationResponse>(
    `vacations/policy-types/${policyTypeId}/cycles`,
    {
      params: {
        page: 1,
        limit: 100,
        userId: userCollaboratorId,
        onlyPositiveBalance: false,
        expired: false,
        orderBy: 'START_DATE',
        order: 'DESC',
      },
    },
  );

export const downloadReportBalances = (
  filters: VacationsFilterValues,
  fileType: string,
  extraFields: ExtraFieldsReport,
  count: number,
) => {
  const responseType = getResponseType(count);
  return api.get<DownloadReportBalancesResponse>('vacations/balances/report', {
    responseType,
    params: {
      fileType,
      ...formatVacationsFilters(filters),
      ...extraFields,
      count,
    },
  });
};

export const downloadReportRequests = (
  filters: VacationsFilterValues,
  fileType: string,
  extraFields: ExtraFieldsReport,
  countRequestManager: number,
) => {
  return api.get('vacations/requests/report', {
    responseType: 'blob',
    params: {
      fileType,
      ...formatVacationsFilters(filters),
      role: Role.MANAGER,
      ...extraFields,
      count: countRequestManager,
    },
  });
};

export const cancelRequest = (requestId: number, resolutionReason: string) =>
  api.put(`vacations/requests/${requestId}/state`, {
    state: VacationStatus.CANCELLED,
    resolutionReason: resolutionReason || undefined,
  });

export const getRequestedDays = (requestData: Partial<RequestTimeOff>) =>
  api.post<TimeOffRequestedDaysResponse>(
    'vacations/requests/preview',
    requestData,
  );

export const getRequestedEditDaysPreview = (
  requestId: number,
  requestData: Partial<RequestTimeOff>,
) =>
  api.post<TimeOffRequestedDaysResponseEdit>(
    `vacations/requests/${requestId}/edit-preview`,
    requestData,
  );

export const editVacationRequest = (
  requestId: number,
  requestData: Partial<RequestTimeOff>,
) =>
  api.put<ResponseRequestTimeOff>(
    `vacations/requests/${requestId}`,
    requestData,
  );

export const getRequestToCalendarManager = (
  params: GetRequestToCalendarParams,
) =>
  api.get<ResponseRequestCalendar>('/vacations/manager/calendar', {
    params: {
      ...formatVacationsFilters(params.filters),
      page: params.page,
      limit: params.limit,
      month: params.month,
    },
  });

export const getRequestToCalendarCollaborator = (
  params: GetRequestToCalendarParams,
) =>
  api.get<ResponseRequestCalendar>('/vacations/collaborator/calendar', {
    params: {
      ...formatVacationsFilters(params.filters),
      page: params.page,
      limit: params.limit,
      month: params.month,
    },
  });

export const massiveApproval = (ids: number[], state: VacationStatus) =>
  api.put(`vacations/requests/approval-steps/state`, {
    state,
    ids,
  });

export const sendReminder = (requestId: number) =>
  api.post(`vacations/requests/${requestId}/remind-approval-users`);

export const updateRequestByEmail = (otc = '', state = '') =>
  api.put<MeResponse>('/time-off/request-approval-step-state', {
    otc,
    state,
  });
