import axiosInstance from "@/utils/axios";
import { create } from "zustand";
import { driverAbsenceEndpoints } from "../endpoints/driverAbsence";
import { IDriverType } from "@/shared/types/driver";

export interface DriverAbsenceList {
  id: number;
  createdAt: string;
  updatedAt: string;
  driverName: string;
  driver: IDriverType;
  absenceType: string;
  startDate: string;
  endDate: string;
  isAssigned: boolean;
  status: DriverAbsenceStatut;
  nbHours: number | null;
  supportingDocumentId: number;
  receptionMode: string;
  validatedBy: number | null;
  authorizedBy: number | null;
  observations: string;
}

export enum DriverAbsenceStatut {
  INVALID = "INVALID",
  IN_PROGRESS = "IN_PROGRESS",
  ACCEPTED = "ACCEPTED",
  REJECTED = "REJECTED",
}

interface Paginated<T> {
  content: T[];
  pageable: { pageNumber: number; pageSize: number };
  totalElements: number;
  totalPages: number;
}

export type Search = {
  page?: number;
  size?: number,
  status?: string,
  absenceType?: string,
  receptionMode?: string,
  driverId?: string,
  isAssigned?: boolean | null,
  driverTraject?: boolean | null
  startDateFrom?: string | null;
  startDateTo?: string | null;
};

export enum DriverAbsenceType {
  AUTHORIZED_ABSENCE = "AUTHORIZED_ABSENCE",
  UNAUTHORIZED_ABSENCE = "UNAUTHORIZED_ABSENCE",
  EXCEPTIONAL_REMOTE_WORK = "EXCEPTIONAL_REMOTE_WORK",
  EXTERNAL_ASSIGNMENT = "EXTERNAL_ASSIGNMENT",
  MEDICAL_APPOINTMENT = "MEDICAL_APPOINTMENT",
}

export enum ReceptionMode {
  MAIL = "MAIL",
  SMS = "SMS",
  PORTAL = "PORTAL",
}

export interface DriverAbsenceRequest {
  driverId: number;
  driverName: string;
  absenceType: string;
  startDate: Date;
  endDate: Date;
  nbHours: number;
  supportingDocumentId: number;
  receptionMode: string;
  observations?: string | null;
  driverTraject: boolean;
  isAssigned: boolean;
  status: string;
  validatedBy?: number | null;
  authorizedBy?: number | null;
}

type Store = {
  processed: DriverAbsenceList[];
  unprocessed: DriverAbsenceList[];
  loading: boolean;
  fetchProcessed: (p: Search) => Promise<void>;
  fetchUnprocessed: (p: Search) => Promise<void>;
  createAbsence: (p: DriverAbsenceRequest) => Promise<void>;
  updateAbsence: (id: string, p: DriverAbsenceRequest) => Promise<void>;
  getAbsenceById: (id: number) => Promise<DriverAbsenceList>;
  changeAbsenceStatus: (id: number, status: string) => Promise<void>;
};

export const useDriverAbsenceStore = create<Store>(set => ({
  processed: [],
  unprocessed: [],
  loading: false,

  fetchProcessed: async params => {
    set({ loading: true });
    const { data } = await axiosInstance.get<Paginated<DriverAbsenceList>>(
      driverAbsenceEndpoints.General.getProcessed,
      { params },
    );
    set({ processed: data.content, loading: false });
  },

  fetchUnprocessed: async params => {
    set({ loading: true });
    const { data } = await axiosInstance.get<Paginated<DriverAbsenceList>>(
      driverAbsenceEndpoints.General.getUnprocessed,
      { params },
    );
    set({ unprocessed: data.content, loading: false });
  },
  createAbsence: async payload => {
    set({ loading: true });
    try {
      const { data } = await axiosInstance.post<DriverAbsenceList>(
        driverAbsenceEndpoints.Create.create,
        payload
      );

      set(s => {
        const addTo = data.status === "IN_PROGRESS" || data.status === "INVALID"
          ? { unprocessed: [...s.unprocessed, data] }
          : { processed: [...s.processed, data] };

        return {
          ...addTo,
          loading: false,
        };
      });
    } catch (e: any) {
      set({ loading: false });
      throw e;
    }
  },
  updateAbsence: async (id: string, payload: DriverAbsenceRequest) => {
    set({ loading: true });
    try {
      const { data } = await axiosInstance.put<DriverAbsenceList>(
        driverAbsenceEndpoints.Update.update(id),
        payload
      );
      set((state) => {
        const updatedUnprocessed = state.unprocessed.map((item) =>
          item.id === data.id ? data : item
        );

        const updatedProcessed = state.processed.map((item) =>
          item.id === data.id ? data : item
        );

        const addTo = data.status === "IN_PROGRESS" || data.status === "INVALID"
          ? { unprocessed: updatedUnprocessed }
          : { processed: updatedProcessed };

        return {
          ...addTo,
          loading: false,
        };
      });
    } catch (e: any) {
      set({ loading: false });
      throw e;
    }
  },
  getAbsenceById: async (id: number) => {
    const { data } = await axiosInstance.get<DriverAbsenceList>(
      driverAbsenceEndpoints.General.getById(id)
    );
    return data;
  }
  ,
  changeAbsenceStatus: async (id: number, status: string) => {
    set({ loading: true });
    try {
      const { data } = await axiosInstance.put<DriverAbsenceList>(
        driverAbsenceEndpoints.Status.changeStatus(id, status)
      );

      set((state) => {
        const updatedUnprocessed = state.unprocessed.map((item) =>
          item.id === data.id ? data : item
        );

        const updatedProcessed = state.processed.map((item) =>
          item.id === data.id ? data : item
        );

        const addTo = data.status === "IN_PROGRESS" || data.status === "INVALID"
          ? { unprocessed: updatedUnprocessed }
          : { processed: updatedProcessed };

        return {
          ...addTo,
          loading: false,
        };
      });
    } catch (e: any) {
      set({ loading: false });
      throw e;
    }
  }
}));
