import { create } from 'zustand';
import axiosInstance from '@/utils/axios';
import {
    AgencyList, AgencyPageFilterParams, AgencyNames, DepartmentNames, LotNumbers, Sector, SectorList, SectorPageFilterParams,
    SectorRequest, AgencyRequest, Agency, SectorNames, Department, DepartmentList, DepartmentPageFilterParams, DepartmentRequest,
    LotList, LotPageFilterParams, Lot, LotRequest
} from '@/shared/types/infrastructure';
import { infrastructureEndpoints } from '../../endpoints/admin-service/infrastructure';

type InfrastructureStore = {
    error: string | null;
    loading: boolean;
    sectorNames: SectorNames[];
    fetchSectorNames: () => Promise<void>;
    agencyNames: AgencyNames[];
    fetchAgencyNames: () => Promise<void>;
    departmentNames: DepartmentNames[];
    fetchDepartmentNames: () => Promise<void>;
    lotNumbers: LotNumbers[];
    fetchLotNumbers: () => Promise<void>;
    departmentNamesByAgencyId: DepartmentNames[];
    fetchDepartmentNamesByAgencyId: (agencyId: number) => Promise<void>;
    lotNumbersByDepartmentId: LotNumbers[];
    fetchLotNumbersByDepartmentId: (departmentId: number) => Promise<void>;
    sectorPage: SectorList[];
    sectorPageTotalElements: number;
    lastUsedSectorParams: SectorPageFilterParams | null;
    fetchSectorPage: (params: SectorPageFilterParams) => Promise<void>;
    toggleSectorActivation: (sectorId: string, isActive: boolean) => Promise<void>;
    sectorById: Sector | null;
    getSectorById: (sectorId: string) => Promise<Sector | null>;
    createSector: (sector: SectorRequest) => Promise<void>;
    updateSector: (sectorId: string, sector: SectorRequest) => Promise<void>;
    agencyPage: AgencyList[];
    agencyPageTotalElements: number;
    lastUsedAgencyParams: AgencyPageFilterParams | null;
    fetchAgencyPage: (params: AgencyPageFilterParams) => Promise<void>;
    toggleAgencyActivation: (agencyId: string, isActive: boolean) => Promise<void>;
    agencyById: Agency | null;
    getAgencyById: (agencyId: string) => Promise<Agency | null>;
    createAgency: (agency: AgencyRequest) => Promise<void>;
    updateAgency: (agencyId: string, agency: AgencyRequest) => Promise<void>;
    departmentPage: DepartmentList[];
    departmentPageTotalElements: number;
    lastUsedDepartmentParams: DepartmentPageFilterParams | null;
    fetchDepartmentPage: (params: DepartmentPageFilterParams) => Promise<void>;
    toggleDepartmentActivation: (departmentId: string, isActive: boolean) => Promise<void>;
    departmentById: Department | null;
    getDepartmentById: (departmentId: string) => Promise<Department | null>;
    createDepartment: (department: DepartmentRequest) => Promise<void>;
    updateDepartment: (departmentId: string, department: DepartmentRequest) => Promise<void>;
    lotPage: LotList[];
    lotPageTotalElements: number;
    lastUsedLotParams: LotPageFilterParams | null;
    fetchLotPage: (params: LotPageFilterParams) => Promise<void>;
    toggleLotActivation: (lotId: string, isActive: boolean) => Promise<void>;
    lotById: Lot | null;
    getLotById: (lotId: string) => Promise<Lot | null>;
    createLot: (lot: LotRequest) => Promise<void>;
    updateLot: (lotId: string, lot: LotRequest) => Promise<void>;
    startExportInfrastructureDataInExcel: (params: SectorPageFilterParams) => Promise<void>;
    exportInfrastructureDataInPdf: (params: SectorPageFilterParams) => Promise<void>;
};

export const useInfrastructureStore = create<InfrastructureStore>((set, get) => ({
    error: null,
    loading: false,
    sectorNames: [],
    fetchSectorNames: async () => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get<SectorNames[]>(infrastructureEndpoints.Sector.getSectorNamesAndIds);
            set({ sectorNames: response.data, loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to fetch sector names', loading: false });
        }
    },
    agencyNames: [],
    fetchAgencyNames: async () => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get<AgencyNames[]>(infrastructureEndpoints.Agency.getAgencyNamesAndIds);
            set({ agencyNames: response.data, loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to fetch agency names', loading: false });
        }
    },
    departmentNames: [],
    fetchDepartmentNames: async () => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get<DepartmentNames[]>(infrastructureEndpoints.Department.getDepartmentNamesAndIds);
            set({ departmentNames: response.data, loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to fetch department names', loading: false });
        }
    },
    departmentNamesByAgencyId: [],
    fetchDepartmentNamesByAgencyId: async (agencyId: number) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get<DepartmentNames[]>(infrastructureEndpoints.Department.getDepartmentNamesAndIdsByAgencyId(agencyId));
            set({ departmentNamesByAgencyId: response.data, loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to fetch department names by agency id', loading: false });
        }
    },
    lotNumbers: [],
    fetchLotNumbers: async () => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get<LotNumbers[]>(infrastructureEndpoints.Lot.getLotNumbersAndIds);
            set({ lotNumbers: response.data, loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to fetch lot numbers', loading: false });
        }
    },
    lotNumbersByDepartmentId: [],
    fetchLotNumbersByDepartmentId: async (departmentId: number) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get<LotNumbers[]>(infrastructureEndpoints.Lot.getLotNumbersAndIdsByDepartmentId(departmentId));
            set({ lotNumbersByDepartmentId: response.data, loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to fetch lot numbers by department id', loading: false });
        }
    },
    sectorPage: [],
    sectorPageTotalElements: 0,
    lastUsedSectorParams: null,
    fetchSectorPage: async (params) => {
        set({ loading: true, error: null });
        set({ lastUsedSectorParams: params });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Sector.getSectorsPage, {
                params,
            });

            const { content, totalElements } = response.data;
            set({
                sectorPage: content,
                sectorPageTotalElements: totalElements,
                loading: false,
            });
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch contracts',
                loading: false,
            });
        }
    },
    toggleSectorActivation: async (sectorId: string, isActive: boolean) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.post<boolean>(infrastructureEndpoints.Sector.toggleSectorActivation(sectorId, isActive));
            set((state) => ({
                sectorPage: state.sectorPage.map((s) => (s.id === sectorId ? { ...s, active: response.data } : s)),
                loading: false,
            }));
        } catch (error: any) {
            set({ error: error.message || 'Failed to toggle sector active', loading: false });
        }
    },
    sectorById: null,
    getSectorById: async (id) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Sector.getSectorById(id));
            set({ loading: false, sectorById: response.data as Sector });
            return response.data as Sector;
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch sector by ID',
                loading: false,
            });
            return null;
        }
    },
    createSector: async (sector: SectorRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Sector.createSector, sector);
            const { lastUsedSectorParams, fetchSectorPage } = get();
            if (lastUsedSectorParams) {
                await fetchSectorPage(lastUsedSectorParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to create sector', loading: false });
        }
    },
    updateSector: async (sectorId: string, sector: SectorRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Sector.updateSector(sectorId), sector);
            const { lastUsedSectorParams, fetchSectorPage } = get();
            if (lastUsedSectorParams) {
                await fetchSectorPage(lastUsedSectorParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to update sector', loading: false });
        }
    },
    agencyPage: [],
    agencyPageTotalElements: 0,
    lastUsedAgencyParams: null,
    fetchAgencyPage: async (params) => {
        set({ loading: true, error: null });
        set({ lastUsedAgencyParams: params });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Agency.getAgencyPage, {
                params,
            });
            const { content, totalElements } = response.data;
            set({
                agencyPage: content,
                agencyPageTotalElements: totalElements,
                loading: false,
            });
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch agency page',
                loading: false,
            });
        }
    },
    toggleAgencyActivation: async (agencyId: string, isActive: boolean) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.post<boolean>(infrastructureEndpoints.Agency.toggleAgencyActivation(agencyId, isActive));
            set((state) => ({
                agencyPage: state.agencyPage.map((a) => (a.id === agencyId ? { ...a, active: response.data } : a)),
                loading: false,
            }));
        } catch (error: any) {
            set({ error: error.message || 'Failed to toggle agency active', loading: false });
        }
    },
    agencyById: null,
    getAgencyById: async (id) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Agency.getAgencyById(id));
            set({ loading: false, agencyById: response.data as Agency });
            return response.data as Agency;
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch agency by ID',
                loading: false,
            });
            return null;
        }
    },
    createAgency: async (agency: AgencyRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Agency.createAgency, agency);
            const { lastUsedAgencyParams, fetchAgencyPage } = get();
            if (lastUsedAgencyParams) {
                await fetchAgencyPage(lastUsedAgencyParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to create agency', loading: false });
        }
    },
    updateAgency: async (agencyId: string, agency: AgencyRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Agency.updateAgency(agencyId), agency);
            const { lastUsedAgencyParams, fetchAgencyPage } = get();
            if (lastUsedAgencyParams) {
                await fetchAgencyPage(lastUsedAgencyParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to update agency', loading: false });
        }
    },
    departmentPage: [],
    departmentPageTotalElements: 0,
    lastUsedDepartmentParams: null,
    fetchDepartmentPage: async (params) => {
        set({ loading: true, error: null });
        set({ lastUsedDepartmentParams: params });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Department.getDepartmentPage, {
                params,
            });
            const { content, totalElements } = response.data;
            set({
                departmentPage: content,
                departmentPageTotalElements: totalElements,
                loading: false,
            });
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch department page',
                loading: false,
            });
        }
    },
    toggleDepartmentActivation: async (departmentId: string, isActive: boolean) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.post<boolean>(infrastructureEndpoints.Department.toggleDepartmentActivation(departmentId, isActive));
            set((state) => ({
                departmentPage: state.departmentPage.map((d) => (d.id === departmentId ? { ...d, active: response.data } : d)),
                loading: false,
            }));
        } catch (error: any) {
            set({ error: error.message || 'Failed to toggle department active', loading: false });
        }
    },
    departmentById: null,
    getDepartmentById: async (id) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Department.getDepartmentById(id));
            set({ loading: false, departmentById: response.data as Department });
            return response.data as Department;
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch department by ID',
                loading: false,
            });
            return null;
        }
    },
    createDepartment: async (department: DepartmentRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Department.createDepartment, department);
            const { lastUsedDepartmentParams, fetchDepartmentPage } = get();
            if (lastUsedDepartmentParams) {
                await fetchDepartmentPage(lastUsedDepartmentParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to create department', loading: false });
        }
    },
    updateDepartment: async (departmentId: string, department: DepartmentRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Department.updateDepartment(departmentId), department);
            const { lastUsedDepartmentParams, fetchDepartmentPage } = get();
            if (lastUsedDepartmentParams) {
                await fetchDepartmentPage(lastUsedDepartmentParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to update department', loading: false });
        }
    },
    lotPage: [],
    lotPageTotalElements: 0,
    lastUsedLotParams: null,
    fetchLotPage: async (params) => {
        set({ loading: true, error: null });
        set({ lastUsedLotParams: params });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Lot.getLotPage, {
                params,
            });
            const { content, totalElements } = response.data;
            set({
                lotPage: content,
                lotPageTotalElements: totalElements,
                loading: false,
            });
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch lot page',
                loading: false,
            });
        }
    },
    toggleLotActivation: async (lotId: string, isActive: boolean) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.post<boolean>(infrastructureEndpoints.Lot.toggleLotActivation(lotId, isActive));
            set((state) => ({
                lotPage: state.lotPage.map((l) => (l.id === lotId ? { ...l, active: response.data } : l)),
                loading: false,
            }));
        } catch (error: any) {
            set({ error: error.message || 'Failed to toggle lot active', loading: false });
        }
    },
    lotById: null,
    getLotById: async (id) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Lot.getLotById(id));
            set({ loading: false, lotById: response.data as Lot });
            return response.data as Lot;
        } catch (error: any) {
            set({
                error: error.message || 'Failed to fetch lot by ID',
                loading: false,
            });
            return null;
        }
    },
    createLot: async (lot: LotRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Lot.createLot, lot);
            const { lastUsedLotParams, fetchLotPage } = get();
            if (lastUsedLotParams) {
                await fetchLotPage(lastUsedLotParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to create lot', loading: false });
        }
    },
    updateLot: async (lotId: string, lot: LotRequest) => {
        set({ loading: true, error: null });
        try {
            await axiosInstance.post(infrastructureEndpoints.Lot.updateLot(lotId), lot);
            const { lastUsedLotParams, fetchLotPage } = get();
            if (lastUsedLotParams) {
                await fetchLotPage(lastUsedLotParams);
            }
            set({ loading: false });
        } catch (error: any) {
            set({ error: error.message || 'Failed to update lot', loading: false });
        }
    },
    startExportInfrastructureDataInExcel: async (params: SectorPageFilterParams) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Sector.startExportInfrastructureDataInExcel, {
                params,
                responseType: 'blob'
            });
            const blob = new Blob([response.data], { type: 'text/csv;charset=utf-8;' });
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.setAttribute('download', 'secteurs.csv');
            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 infrastructure data in csv', loading: false });
        }
    },
    exportInfrastructureDataInPdf: async (params: SectorPageFilterParams) => {
        set({ loading: true, error: null });
        try {
            const response = await axiosInstance.get(infrastructureEndpoints.Sector.exportInfrastructureDataInPdf, {
                params,
                responseType: 'blob'
            });
            const blob = new Blob([response.data], { type: 'application/pdf' });
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.setAttribute('download', 'secteurs.pdf');
            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 infrastructure data in pdf', loading: false });
        }
    }
}));