import { create } from 'zustand';
import axiosInstance from '@/utils/axios';
import { Establishment, EstablishmentPageFilterParams, EstablishmentNameAndId, EstablishmentRequest, EstablishmentHoursResponse, UpdateEstablishmentHoursRequest, IHolidayGeneral, IHolidayImport, IHolidayImportFilterParams, IHolidayCalendarFilterParams } from '@/shared/types/establishment';
import { establishmentEndpoints } from '../../endpoints/admin-service/establishment-endpoints';

type EstablishmentStore = {
  loading: boolean;
  error: string | null;
  clearError: () => void;
  establishments: Establishment[];
  establishmentNamesAndIds: EstablishmentNameAndId[];
  totalElements: number;
  lastUsedEstablishmentParams: EstablishmentPageFilterParams | null;
  fetchEstablishmentsPage: (params?: EstablishmentPageFilterParams) => Promise<void>;
  toogleActivation: (id: string, isActive: boolean) => Promise<void>;
  establishmentById: Establishment | null;
  getEstablishmentById: (id: string) => Promise<Establishment>;
  getAllEstablishmentNamesAndIds: () => Promise<void>;
  createEstablishment: (establishment: EstablishmentRequest) => Promise<void>;
  updateEstablishment: (id: string, establishment: EstablishmentRequest) => Promise<void>;
  startExportFiltredEstablishments: (params?: EstablishmentPageFilterParams) => Promise<void>;
  exportHolidaysExcelTemplate: (populationType: string, filled: boolean) => Promise<void>;
  importHolidaysExcel: (file: File, populationType: string, ownerId: string) => Promise<void>;
  createHolidayImport: (formData: IHolidayImport) => Promise<void>;
  holidaysListByYear: IHolidayGeneral[];
  getHolidaysListByYear: (year: number) => Promise<void>;
  holidaysListByYearAndMonth: IHolidayGeneral[];
  getHolidaysListByYearAndMonth: (year: number, monthIndex: number) => Promise<void>;
  holidayImportPage: IHolidayImport[];
  lastUsedHolidayImportParams: IHolidayImportFilterParams | null;
  totalElementsHolidayImport: number;
  getHolidayImportPage: (params: IHolidayImportFilterParams) => Promise<void>;
  startCsvExportHolidays: (params: IHolidayCalendarFilterParams) => Promise<void>;
  existsEstablishmentByCodeLoading: boolean;
  existsEstablishmentByCode: (code: string, excludeId?: number) => Promise<boolean>;
  existsEstablishmentByUaiCodeLoading: boolean;
  existsEstablishmentByUaiCode: (uaiCode: string, excludeId?: number) => Promise<boolean>;
  searchWithSpecificInfoLoading: boolean;
  searchWithSpecificInfo: (keyword?: string, id?: string, externalSignal?: AbortSignal) => Promise<void>;
  establishmentHoursById: EstablishmentHoursResponse[];
  establishmentHoursLoading: boolean;
  getEstablishmentHoursById: (id: string) => Promise<EstablishmentHoursResponse[]>;
  updateEstablishmentHours: (id: string, request: UpdateEstablishmentHoursRequest) => Promise<void>;
};

export const useEstablishmentStore = create<EstablishmentStore>((set, get) => ({
  loading: false,
  error: null,
  clearError: () => set({ error: null }),
  establishments: [],
  establishmentNamesAndIds: [],
  totalElements: 0,
  lastUsedEstablishmentParams: null,
  fetchEstablishmentsPage: async (params) => {
    set({ loading: true, error: null });
    set({ lastUsedEstablishmentParams: params });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.getEstablishmentsPage, {
        params,
      });

      const { content, totalElements } = response.data;
      set({
        establishments: content,
        totalElements,
        loading: false,
      });
    } catch (error: any) {
      set({
        error: error.message || 'Failed to fetch establishments',
        loading: false,
      });
    }
  },
  toogleActivation: async (id: string, active: boolean) => {
    set({ loading: true, error: null });
    try {
      await axiosInstance.patch<boolean>(establishmentEndpoints.toggleActivation(id, active));
      const { lastUsedEstablishmentParams, fetchEstablishmentsPage } = get();
      if (lastUsedEstablishmentParams) {
        await fetchEstablishmentsPage(lastUsedEstablishmentParams);
      }
      set({ loading: false });
    } catch (error: any) {
      set({
        error: error.message || 'Failed to toggle activation',
        loading: false,
      });
    }
  },
  establishmentById: null,
  getEstablishmentById: async (id: string) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.getEstablishmentById(id));
      set({
        establishmentById: response.data,
        loading: false,
      });
      return response.data;
    } catch (error: any) {
      set({
        error: error.message || 'Failed to get establishment by id',
        loading: false,
      });
    }
  },
  getAllEstablishmentNamesAndIds: async () => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.getAllEstablishmentNamesAndIds);
      set({ establishmentNamesAndIds: response.data, loading: false });
    } catch (error: any) {
      set({
        error: error.message || 'Failed to get establishment names and ids',
        loading: false,
      });
      throw error;
    }
  },
  createEstablishment: async (establishment: EstablishmentRequest) => {
    set({ loading: true, error: null });
    try {
      await axiosInstance.post(establishmentEndpoints.createEstablishment, establishment);
      const { lastUsedEstablishmentParams, fetchEstablishmentsPage } = get();
      if (lastUsedEstablishmentParams) {
        await fetchEstablishmentsPage(lastUsedEstablishmentParams);
      }
      set({ loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to create establishment', loading: false });
      throw error;
    }
  },
  updateEstablishment: async (id: string, establishment: EstablishmentRequest) => {
    set({ loading: true, error: null });
    try {
      await axiosInstance.put(establishmentEndpoints.updateEstablishment(id), establishment);
      const { lastUsedEstablishmentParams, fetchEstablishmentsPage } = get();
      if (lastUsedEstablishmentParams) {
        await fetchEstablishmentsPage(lastUsedEstablishmentParams);
      }
      set({ loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to update establishment', loading: false });
      throw error;
    }
  },
  startExportFiltredEstablishments: async (params?: EstablishmentPageFilterParams) => {
    set({ loading: true, error: null });
    try {
      const userId = typeof window !== 'undefined' ? localStorage.getItem('userId') : null;
      const response = await axiosInstance.post(
        establishmentEndpoints.startExportFiltredEstablishments,
        { params },
        userId ? { params: { userId } } : undefined
      );
      return response.data;
    } catch (error: any) {
      set({
        error: error.message || 'Failed to start export filtred establishments',
        loading: false,
      });
    }
  },
  holidaysListByYear: [],
  getHolidaysListByYear: async (year: number) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.holidays.getHolidaysListByYear(year));
      set({ holidaysListByYear: response.data, loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to get holidays by year', loading: false });
    }
  },
  holidaysListByYearAndMonth: [],
  getHolidaysListByYearAndMonth: async (year: number, monthIndex: number) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.holidays.getHolidaysListByYearAndMonth(year, monthIndex));
      set({ holidaysListByYearAndMonth: response.data, loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to get holidays by year and month', loading: false });
    }
  },
  exportHolidaysExcelTemplate: async (populationType: string, filled: boolean) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.holidays.exportExcelTemplate, {
        params: {
          populationType,
          filled,
        },
        responseType: 'blob'
      });
      const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.setAttribute('download', 'holidays.xlsx');
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(url);
      set({ loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to export excel template', loading: false });
    }
  },
  importHolidaysExcel: async (file: File, populationType: string, ownerId: string) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.post(establishmentEndpoints.holidays.importHolidaysExcel, {
        params: {
          file,
          populationType,
          ownerId,
        },
      });
      return response.data;
    } catch (error: any) {
      set({ error: error.message || 'Failed to import holidays', loading: false });
    }
  },
  createHolidayImport: async (formData: IHolidayImport) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.post(establishmentEndpoints.holidays.createHolidayImport, formData);
      const { getHolidaysListByYearAndMonth } = get();
      await getHolidaysListByYearAndMonth(new Date().getFullYear(), new Date().getMonth());
      set({ loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to import holidays', loading: false });
    }
  },
  holidayImportPage: [],
  totalElementsHolidayImport: 0,
  lastUsedHolidayImportParams: null,
  getHolidayImportPage: async (params: IHolidayImportFilterParams) => {
    set({ loading: true, error: null });
    set({ lastUsedHolidayImportParams: params });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.holidays.getHolidayImportPage, { params });
      const { content, totalElements } = response.data;
      set({ holidayImportPage: content, totalElementsHolidayImport: totalElements, loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to get holiday import page', loading: false });
    }
  },
  startCsvExportHolidays: async (params: IHolidayCalendarFilterParams) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.post(establishmentEndpoints.holidays.startCsvExportHolidays, null, {
        params,
      });
      set({ loading: false });
      return response.data;
    } catch (error: any) {
      set({ error: error.message || 'Failed to start csv export holidays', loading: false });
    }
  },
  existsEstablishmentByCodeLoading: false,
  existsEstablishmentByCode: async (code: string, excludeId?: number) => {
    set({ existsEstablishmentByCodeLoading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.existsEstablishmentByCode, {
        params: {
          code,
          excludeId
        }
      });
      set({ existsEstablishmentByCodeLoading: false });
      return response.data;
    } catch (error: any) {
      set({ error: error.message || 'Failed to check if establishment exists by code', existsEstablishmentByCodeLoading: false });
    }
  },
  existsEstablishmentByUaiCodeLoading: false,
  existsEstablishmentByUaiCode: async (uaiCode: string, excludeId?: number) => {
    set({ existsEstablishmentByUaiCodeLoading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.existsEstablishmentByUaiCode, {
        params: {
          uaiCode,
          excludeId
        }
      });
      set({ existsEstablishmentByUaiCodeLoading: false });
      return response.data;
    } catch (error: any) {
      set({ error: error.message || 'Failed to check if establishment exists by uai code', existsEstablishmentByUaiCodeLoading: false });
    }
  },
  searchWithSpecificInfoLoading: false,
  searchWithSpecificInfo: async (keyword?: string, id?: string, externalSignal?: AbortSignal) => {
    set({ searchWithSpecificInfoLoading: true, error: null, establishmentNamesAndIds: [] });
    
    try {
      const params = {
        ...(keyword && { keyword }),
        ...(id && { id }),
      }

      const response = await axiosInstance.get(establishmentEndpoints.searchWithSpecificInfo, {
        params,
        signal: externalSignal,
      })

      if (!externalSignal?.aborted) {
        set({ searchWithSpecificInfoLoading: false, establishmentNamesAndIds: response.data });
      }
    } catch (error: any) {
      if (error.name !== "CanceledError" && error.code !== "ERR_CANCELED") {
        set({ 
          error: error.message || 'Failed to search establishments with specific info', 
          searchWithSpecificInfoLoading: false 
        });
        throw error;
      }
    }
  },
  establishmentHoursById: [],
  establishmentHoursLoading: false,
  getEstablishmentHoursById: async (id: string) => {
    set({ establishmentHoursLoading: true, error: null });
    try {
      const response = await axiosInstance.get(establishmentEndpoints.getEstablishmentHoursById(id));
      set({ 
        establishmentHoursById: response.data, 
        establishmentHoursLoading: false 
      });
      return response.data;
    } catch (error: any) {
      set({ 
        error: error.message || 'Erreur lors de la récupération des horaire', 
        establishmentHoursLoading: false 
      });
      throw error;
    }
  },
  updateEstablishmentHours: async (id: string, request: UpdateEstablishmentHoursRequest) => {
    set({ establishmentHoursLoading: true, error: null });
    try {
      const response = await axiosInstance.patch(establishmentEndpoints.updateEstablishmentHours(id), request);
      set({ 
        establishmentHoursById: response.data, 
        establishmentHoursLoading: false 
      });
    } catch (error: any) {
      set({ 
        error: error.message || 'Erreur lors de la mise à jour des horaires',
        establishmentHoursLoading: false 
      });
      throw error;
    }
  }
}));