import api from 'src/config/api';
import {
  Shift,
  ShiftCalendarUser,
  ShiftFilterUser,
  ShiftAssignCellVC,
  ShiftRotation,
  ShiftRotationDetail,
} from 'src/types/shifts';
import { PaginatedResponse, PaginationParams } from 'src/utils/pagination';

export enum ShiftErrorCodes {
  SHIFT_MANAGEMENT_REST_SHIFT_OVERLAP = 'SHIFT_MANAGEMENT_REST_SHIFT_OVERLAP',
  SHIFT_MANAGEMENT_INVALID_TIME_SLOTS = 'SHIFT_MANAGEMENT_INVALID_TIME_SLOTS',
}

export type ShiftCalendarResponse = PaginatedResponse<ShiftCalendarUser> & {
  total: number;
};

export type ShiftCalendarParams = PaginationParams & {
  startDate: string;
  endDate: string;
  userIds?: string;
  search?: string;
};

export type ShiftRegionParams = PaginationParams & {
  search?: string;
};

export type ShiftRegion = {
  id: number;
  title: string;
  sites: {
    id: number;
    name: string;
  }[];
};

export type ShiftRegionResponse = PaginatedResponse<ShiftRegion>;

export type ShiftUsersParams = PaginationParams & {
  siteId?: number;
};

export const getShiftCalendar = (
  params: ShiftCalendarParams,
  signal: AbortSignal | undefined,
) =>
  api.get<ShiftCalendarResponse>('shifts/calendar', {
    params,
    signal,
  });

export const getShiftRegions = (
  params: ShiftRegionParams,
  signal?: AbortSignal,
) =>
  api.get<ShiftRegionResponse>('/shifts/regions', {
    params,
    signal,
  });

export const getUsers = (params: ShiftUsersParams) => {
  // Endpoint will throw error if search is falsy (undefined, null, empty string)
  if (!params.search) {
    delete params.search;
  }
  if (!params.siteId) {
    delete params.siteId;
  }
  return api.get<PaginatedResponse<ShiftFilterUser>>('/shifts/users', {
    params,
  });
};

export type AssignedShiftInfo = {
  name?: string;
  color?: string;
  description?: string;
  isRest?: boolean;
  isHalfDayRest?: boolean;
  timeSlots?: [string, string][];
  saveAsTemplate?: boolean;
};

export type SearchType = 'ALL' | 'ACTIVE' | 'INACTIVE';

export type ShiftManagementCalendarFiltersVC = {
  startDate: string;
  endDate: string;
  segmentationItemIds?: number[];
  siteId?: number;
  searchType?: SearchType;
  userIds: number[];
  search?: string;
};

export type AssignShiftParams = {
  allRows?: boolean;
  userIds?: number[];
  dates?: string[];
  cells?: ShiftAssignCellVC[];
  excludeCells?: ShiftAssignCellVC[];
  filters?: ShiftManagementCalendarFiltersVC;
  shift: AssignedShiftInfo;
};

export type BulkDeleteShiftParams = {
  allRows?: boolean;
  userIds?: number[];
  dates?: string[];
  cells?: ShiftAssignCellVC[];
  excludeCells?: ShiftAssignCellVC[];
  filters?: ShiftManagementCalendarFiltersVC;
  assignedShiftIds?: number[];
  excludeAssignedShiftIds?: number[];
};

export const assignShift = (data: AssignShiftParams) =>
  api.post('shifts/assign', data);

export const bulkDeleteShift = (data: BulkDeleteShiftParams) =>
  api.post('shifts/bulk-delete', data);

export type RemoveDayAssignmentParams = {
  shiftAssignedDayId: number;
  shiftAssignedShiftId: number;
};

export const removeDayAssignment = ({
  shiftAssignedDayId,
  shiftAssignedShiftId,
}: RemoveDayAssignmentParams) =>
  api.delete(
    `shifts/${shiftAssignedDayId}/assignments/${shiftAssignedShiftId}`,
  );

export type ShiftsRepositoryParams = Omit<PaginationParams, 'limit'> & {
  search?: string;
};

export type ShiftCopy = {
  sourceUserId: number;
  dates?: string[];
  assignedShiftIds?: number[];
};

export type ShiftPasteUser = {
  targetUserId: number;
  startDate: string;
};

export type ShiftPaste = {
  allUsers?: boolean;
  startDate?: string;
  excludeTargetUserIds?: number[];
  filters?: ShiftManagementCalendarFiltersVC;
  users?: ShiftPasteUser[];
};

export type ShiftCopyPasteParams = {
  copy: ShiftCopy;
  paste: ShiftPaste;
};

export const copyAndPasteShifts = (data: ShiftCopyPasteParams) =>
  api.post('shifts/copy-and-paste', data);

// SHIFT REPOSITORY

export type ShiftTemplateParams = {
  name: string;
  color: string;
  description?: string;
  timeSlots: [string, string][];
};

export const getShiftsRepository = (params: ShiftsRepositoryParams) =>
  api.get<PaginatedResponse<Shift>>('shifts/templates', {
    params: { ...params, limit: 20 },
  });

export const createShiftTemplate = (data: ShiftTemplateParams) =>
  api.post<Shift>('shifts/templates', data);

export const editShiftTemplate = (
  id: number,
  data: Partial<ShiftTemplateParams>,
) => api.put(`shifts/templates/${id}`, data);

export const deleteShiftTemplate = (id: number) =>
  api.delete(`shifts/templates/${id}`);

// DUPLICATE SHIFTS

export type DuplicateShiftsParams = {
  sourceStartDate: string;
  sourceEndDate: string;
  targetStartDate: string;
  targetEndDate: string;
  filters?: ShiftManagementCalendarFiltersVC;
};

export const duplicateShiftsInPeriod = (params: DuplicateShiftsParams) =>
  api.post('shifts/duplicate-period', params);

export type ShiftMoveItem = {
  shiftAssignedShiftId: number;
  targetUserId: number;
  targetDate: string;
};

export type MoveShiftsParams = {
  moves: ShiftMoveItem[];
};

export const moveShifts = (params: MoveShiftsParams) =>
  api.post('shifts/move', params);

// SHIFT ROTATIONS (templates of rotating schedules)

export type ShiftRotationsParams = {
  search?: string;
  limit: number;
  page: number;
};

export type ShiftRotationDayShiftVC = {
  // On create: omit shiftCode (server generates). On update: echo for shifts
  // that already existed; omit for new ones.
  shiftCode?: string;
  name: string;
  color?: string;
  description?: string;
  timeSlots: [string, string][];
};

export type ShiftRotationDayVC = {
  type: 'WORK' | 'REST';
  // WORK: 1..3 shifts. REST: must be [].
  shifts: ShiftRotationDayShiftVC[];
};

export type CreateOrUpdateShiftRotationVC = {
  name: string;
  description?: string;
  days: ShiftRotationDayVC[]; // 1..28
};

export const ShiftRotationErrorCodes = {
  SHIFT_ROTATION_NOT_FOUND: 'SHIFT_ROTATION_NOT_FOUND',
  SHIFT_ROTATION_OVERLAPPING_SHIFTS: 'SHIFT_ROTATION_OVERLAPPING_SHIFTS',
  SHIFT_ROTATION_INVALID_SHIFT_CODE: 'SHIFT_ROTATION_INVALID_SHIFT_CODE',
} as const;
export type ShiftRotationErrorCodes =
  (typeof ShiftRotationErrorCodes)[keyof typeof ShiftRotationErrorCodes];

export const getShiftRotations = (params: ShiftRotationsParams) =>
  api.get<PaginatedResponse<ShiftRotation>>('shift-rotations', {
    params,
  });

export const getShiftRotationById = (id: string) =>
  api.get<ShiftRotationDetail>(`shift-rotations/${id}`);

export const createShiftRotation = (data: CreateOrUpdateShiftRotationVC) =>
  api.post<ShiftRotation>('shift-rotations', data);

export const updateShiftRotation = (
  id: string,
  data: CreateOrUpdateShiftRotationVC,
) => api.put<ShiftRotation>(`shift-rotations/${id}`, data);

export const deleteShiftRotation = (id: string) =>
  api.delete(`shift-rotations/${id}`);

export type AssignShiftRotationVC = {
  userIds: number[];
  startDate: string; // YYYY-MM-DD
};

export const assignShiftRotation = (id: string, data: AssignShiftRotationVC) =>
  api.post(`shift-rotations/${id}/assign`, data);
