import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import {
  candidatesApi,
  CandidateDTO,
  CreateCandidateRequest,
  SendEmailRequest,
  SendFormRequest,
  PageResponse,
  ExportCandidateRequest,
  ExportCandidateResponse,
} from '../../endpoints/hr/candidates';
import { enqueueSnackbar } from 'notistack';

export type CandidateStatus =
  | 'TO_PROCESS'
  | 'IN_PROGRESS'
  | 'RETAINED'
  | 'VALIDATED'
  | 'REFUSED'
  | 'BLACKLISTED'
  | 'ABSENT';
export type CandidateType = 'DRIVER' | 'SEDENTARY';

export interface Department {
  id: number;
  name: string;
}

export interface CandidatesState {
  candidates: CandidateDTO[];
  currentCandidate: CandidateDTO | null;
  totalElements: number;
  totalPages: number;
  currentPage: number;
  pageSize: number;

  loading: boolean;
  creating: boolean;
  updating: boolean;
  deleting: boolean;
  sendingEmail: boolean;
  sendingForm: boolean;

  currentStatus: CandidateStatus | null;
  currentType: CandidateType | null;
  searchQuery: string;

  statistics: Record<string, number>;

  departments: Department[];
  departmentsLoading: boolean;
  fetchCandidates: (page?: number, size?: number) => Promise<void>;
  fetchCandidatesByStatus: (
    status: CandidateStatus,
    type?: CandidateType,
    page?: number,
    size?: number
  ) => Promise<void>;
  fetchCandidatesByType: (type: CandidateType, page?: number, size?: number) => Promise<void>;
  fetchRdvSemaineCandidates: (type?: CandidateType, page?: number, size?: number) => Promise<void>;
  fetchAbsentCandidates: (type?: CandidateType, page?: number, size?: number) => Promise<void>;
  fetchRefusedAndBlacklistedCandidates: (
    type?: CandidateType,
    page?: number,
    size?: number
  ) => Promise<void>;
  fetchCandidateById: (id: string) => Promise<void>;
  searchCandidates: (query: string, page?: number, size?: number) => Promise<void>;
  searchCandidatesAdvanced: (
    filters: Record<string, any>,
    page?: number,
    size?: number
  ) => Promise<void>;
  createCandidate: (data: CreateCandidateRequest) => Promise<string | null>;
  updateCandidate: (id: string, data: Partial<CandidateDTO>) => Promise<void>;
  deleteCandidate: (id: string) => Promise<void>;
  updateCandidateStatus: (id: string, status: CandidateStatus, reason?: string) => Promise<void>;
  scheduleRdv: (id: string, rdvDateTime: string) => Promise<void>;
  markAsAbsent: (id: string) => Promise<void>;
  replanifyRdv: (id: string, rdvDateTime: string) => Promise<void>;
  sendEmailToCandidate: (data: SendEmailRequest) => Promise<void>;
  sendFormToCandidate: (data: SendFormRequest) => Promise<void>;
  fetchStatistics: () => Promise<void>;
  bulkUpdateStatus: (
    candidateIds: string[],
    status: CandidateStatus,
    reason?: string
  ) => Promise<void>;
  bulkSendEmail: (candidateIds: string[], subject: string, message: string) => Promise<void>;

  exporting: boolean;
  exportProgress: number;

  setCurrentStatus: (status: CandidateStatus | null) => void;
  setCurrentType: (type: CandidateType | null) => void;
  setSearchQuery: (query: string) => void;
  setPage: (page: number) => void;
  setPageSize: (size: number) => void;
  clearFilters: () => void;

  resetState: () => void;

  exportCandidates: (exportData: ExportCandidateRequest) => Promise<string | null>;
  downloadExportFile: (filePath: string) => Promise<void>;
  fetchDepartments: () => Promise<void>;
}

const initialState = {
  candidates: [],
  currentCandidate: null,
  totalElements: 0,
  totalPages: 0,
  currentPage: 0,
  pageSize: 20,
  loading: false,
  creating: false,
  updating: false,
  deleting: false,
  sendingEmail: false,
  sendingForm: false,
  currentStatus: null,
  currentType: 'DRIVER' as CandidateType,
  searchQuery: '',
  statistics: {},
  departments: [],
  departmentsLoading: false,
  exporting: false,
  exportProgress: 0,
};

export const useCandidatesStore = create<CandidatesState>()(
  devtools(
    (set, get) => ({
      ...initialState,

      fetchCandidates: async (page = 0, size = 20) => {
        set({ loading: true });
        try {
          const response = await candidatesApi.getAllCandidates(page, size);
          set({
            candidates: response.content,
            totalElements: response.totalElements,
            totalPages: response.totalPages,
            currentPage: page,
            pageSize: size,
            loading: false,
          });
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement des candidats', { variant: 'error' });
          set({ loading: false });
        }
      },

      fetchCandidatesByStatus: async (status, type, page = 0, size = 20) => {
        set({ loading: true, currentStatus: status, currentType: type });
        try {
          const response = await candidatesApi.getCandidatesByStatus(status, type, page, size);
          set({
            candidates: response.content,
            totalElements: response.totalElements,
            totalPages: response.totalPages,
            currentPage: page,
            pageSize: size,
            loading: false,
          });
          return response.content;
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement des candidats', { variant: 'error' });
          set({ loading: false });
          return [];
        }
      },

      fetchCandidatesByType: async (type, page = 0, size = 20) => {
        set({ loading: true, currentType: type });
        try {
          const response = await candidatesApi.getCandidatesByType(type, page, size);
          set({
            candidates: response.content,
            totalElements: response.totalElements,
            totalPages: response.totalPages,
            currentPage: page,
            pageSize: size,
            loading: false,
          });
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement des candidats', { variant: 'error' });
          set({ loading: false });
        }
      },

      fetchRdvSemaineCandidates: async (type, page = 0, size = 20) => {
        set({ loading: true, currentType: type });
        try {
          const rdvResponse = await candidatesApi.getRdvSemaineCandidates(type, page, 1000);
          let allCandidatesWithRdv = [...rdvResponse.content];

          try {
            const retainedResponse = await candidatesApi.getCandidatesByStatus(
              'RETAINED',
              type,
              0,
              1000
            );
            const retainedWithRdv = retainedResponse.content.filter(
              (candidate) =>
                candidate.agencyAppointmentDateTime &&
                !allCandidatesWithRdv.some((existing) => existing.id === candidate.id)
            );
            allCandidatesWithRdv = [...allCandidatesWithRdv, ...retainedWithRdv];
          } catch (retainedError) {}

          try {
            const absentResponse = await candidatesApi.getAbsentCandidates(type, 0, 1000);
            const absentWithRdv = absentResponse.content.filter(
              (candidate) =>
                candidate.agencyAppointmentDateTime &&
                !allCandidatesWithRdv.some((existing) => existing.id === candidate.id)
            );
            allCandidatesWithRdv = [...allCandidatesWithRdv, ...absentWithRdv];
          } catch (absentError) {}

          const candidatesWithRdv = allCandidatesWithRdv.filter(
            (candidate) => !!candidate.agencyAppointmentDateTime
          );

          set({
            candidates: candidatesWithRdv,
            totalElements: candidatesWithRdv.length,
            totalPages: Math.ceil(candidatesWithRdv.length / size),
            currentPage: page,
            pageSize: size,
            loading: false,
          });
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement des candidats', { variant: 'error' });
          set({ loading: false });
        }
      },

      fetchAbsentCandidates: async (type, page = 0, size = 20) => {
        set({ loading: true, currentType: type });
        try {
          const response = await candidatesApi.getAbsentCandidates(type, page, size);
          set({
            candidates: response.content,
            totalElements: response.totalElements,
            totalPages: response.totalPages,
            currentPage: page,
            pageSize: size,
            loading: false,
          });
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement des absents', { variant: 'error' });
          set({ loading: false });
        }
      },

      fetchRefusedAndBlacklistedCandidates: async (type, page = 0, size = 20) => {
        set({ loading: true, currentType: type });
        try {
          const response = await candidatesApi.getRefusedAndBlacklistedCandidates(type, page, size);
          set({
            candidates: response.content,
            totalElements: response.totalElements,
            totalPages: response.totalPages,
            currentPage: page,
            pageSize: size,
            loading: false,
          });
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement des refusés', { variant: 'error' });
          set({ loading: false });
        }
      },

      fetchCandidateById: async (id) => {
        set({ loading: true });
        try {
          const candidate = await candidatesApi.getCandidateById(id);
          set({ currentCandidate: candidate, loading: false });
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement du candidat', { variant: 'error' });
          set({ loading: false });
        }
      },

      searchCandidates: async (query, page = 0, size = 20) => {
        set({ loading: true, searchQuery: query });
        try {
          const response = await candidatesApi.searchCandidates(query, page, size);
          set({
            candidates: response.content,
            totalElements: response.totalElements,
            totalPages: response.totalPages,
            currentPage: page,
            pageSize: size,
            loading: false,
          });
        } catch (error) {
          enqueueSnackbar('Erreur lors de la recherche', { variant: 'error' });
          set({ loading: false });
        }
      },

      searchCandidatesAdvanced: async (filters, page = 0, size = 20) => {
        set({ loading: true });
        try {
          const response = await candidatesApi.searchCandidatesAdvanced(filters, page, size);
          set({
            candidates: response.content,
            totalElements: response.totalElements,
            totalPages: response.totalPages,
            currentPage: page,
            pageSize: size,
            loading: false,
          });
        } catch (error: any) {
          const message = error.response?.data?.message || 'Erreur lors de la recherche avancée';
          enqueueSnackbar(message, { variant: 'error' });
          set({ loading: false });
        }
      },

      createCandidate: async (data) => {
        set({ creating: true });
        try {
          const result = await candidatesApi.createCandidate(data);
          enqueueSnackbar('Candidat créé avec succès', { variant: 'success' });

          try {
            const { currentStatus, currentType, currentPage, pageSize } = get();
            if (currentStatus) {
              await get().fetchCandidatesByStatus(
                currentStatus,
                currentType || undefined,
                currentPage,
                pageSize
              );
            } else {
              await get().fetchCandidates(currentPage, pageSize);
            }
          } catch (refreshError) {}

          set({ creating: false });

          let candidateId = null;
          try {
            const match = result.message?.match(/ID: ([^)]+)/);
            candidateId = match ? match[1] : null;
          } catch (parseError) {}

          return candidateId;
        } catch (error: any) {
          const backendCode = error?.response?.data?.code;
          const backendMessage = error?.response?.data?.message;
          let message = backendMessage || 'Erreur lors de la création du candidat';

          if (backendCode === '001') {
            message = 'Un candidat avec cet email existe déjà';
          }

          enqueueSnackbar(message, { variant: 'error' });
          set({ creating: false });
          return null;
        }
      },

      updateCandidate: async (id, data) => {
        set({ updating: true });
        try {
          await candidatesApi.updateCandidate(id, data);
          enqueueSnackbar('Candidat mis à jour avec succès', { variant: 'success' });

          const { candidates } = get();
          const updatedCandidates = candidates.map((candidate) =>
            candidate.id === id ? { ...candidate, ...data } : candidate
          );
          set({ candidates: updatedCandidates, updating: false });

          const { currentCandidate } = get();
          if (currentCandidate?.id === id) {
            set({ currentCandidate: { ...currentCandidate, ...data } });
          }
        } catch (error: any) {
          const message = error.response?.data?.message || 'Erreur lors de la mise à jour';
          enqueueSnackbar(message, { variant: 'error' });
          set({ updating: false });
        }
      },

      deleteCandidate: async (id) => {
        set({ deleting: true });
        try {
          await candidatesApi.deleteCandidate(id);
          enqueueSnackbar('Candidat supprimé avec succès', { variant: 'success' });

          const { candidates } = get();
          const filteredCandidates = candidates.filter((candidate) => candidate.id !== id);
          set({ candidates: filteredCandidates, deleting: false });

          const { currentCandidate } = get();
          if (currentCandidate?.id === id) {
            set({ currentCandidate: null });
          }
        } catch (error: any) {
          const message = error.response?.data?.message || 'Erreur lors de la suppression';
          enqueueSnackbar(message, { variant: 'error' });
          set({ deleting: false });
        }
      },

      updateCandidateStatus: async (id, status, reason) => {
        set({ updating: true });
        try {
          await candidatesApi.updateCandidateStatus(id, status, reason);
          enqueueSnackbar('Statut mis à jour avec succès', { variant: 'success' });

          const { candidates } = get();
          const updatedCandidates = candidates.map((candidate) =>
            candidate.id === id ? { ...candidate, status } : candidate
          );
          set({ candidates: updatedCandidates, updating: false });
        } catch (error: any) {
          const message = error.response?.data?.message || 'Erreur lors du changement de statut';
          enqueueSnackbar(message, { variant: 'error' });
          set({ updating: false });
        }
      },

      scheduleRdv: async (id, rdvDateTime) => {
        set({ updating: true });
        try {
          await candidatesApi.scheduleRdv(id, rdvDateTime);
          enqueueSnackbar('RDV planifié avec succès', { variant: 'success' });

          const { candidates } = get();
          const updatedCandidates = candidates.map((candidate) =>
            candidate.id === id ? { ...candidate, rdvAgencyDateTime: rdvDateTime } : candidate
          );
          set({ candidates: updatedCandidates, updating: false });
        } catch (error: any) {
          const message = error.response?.data?.message || 'Erreur lors de la planification du RDV';
          enqueueSnackbar(message, { variant: 'error' });
          set({ updating: false });
        }
      },

      markAsAbsent: async (id) => {
        set({ updating: true });
        try {
          await candidatesApi.markAsAbsent(id);

          const { candidates } = get();
          const candidate = candidates.find((c) => c.id === id);
          const candidateName = candidate
            ? `${candidate.firstName} ${candidate.lastName}`
            : 'Candidat';

          enqueueSnackbar(`${candidateName} marqué comme absent au RDV`, { variant: 'success' });

          const updatedCandidates = candidates.filter((c) => c.id !== id);
          set({ candidates: updatedCandidates, updating: false });
        } catch (error: any) {
          const message = error.response?.data?.message || 'Erreur lors du marquage comme absent';
          enqueueSnackbar(message, { variant: 'error' });
          set({ updating: false });
        }
      },

      replanifyRdv: async (id, rdvDateTime) => {
        set({ updating: true });
        try {
          await candidatesApi.replanifyRdv(id, rdvDateTime);

          const { candidates } = get();
          const candidate = candidates.find((c) => c.id === id);
          const candidateName = candidate
            ? `${candidate.firstName} ${candidate.lastName}`
            : 'Candidat';

          const rdvDate = new Date(rdvDateTime);
          const formattedDate = rdvDate.toLocaleString('fr-FR', {
            weekday: 'long',
            year: 'numeric',
            month: 'long',
            day: 'numeric',
            hour: '2-digit',
            minute: '2-digit',
          });

          enqueueSnackbar(`RDV replanifié pour ${candidateName} le ${formattedDate}`, {
            variant: 'success',
          });

          const updatedCandidates = candidates.filter((c) => c.id !== id);
          set({ candidates: updatedCandidates, updating: false });
        } catch (error: any) {
          const message =
            error.response?.data?.message || 'Erreur lors de la replanification du RDV';
          enqueueSnackbar(message, { variant: 'error' });
          set({ updating: false });
        }
      },

      sendEmailToCandidate: async (data) => {
        set({ sendingEmail: true });
        try {
          await candidatesApi.sendEmailToCandidate(data);
          enqueueSnackbar('Email envoyé avec succès', { variant: 'success' });
          set({ sendingEmail: false });
        } catch (error: any) {
          const message = error.response?.data?.message || "Erreur lors de l'envoi de l'email";
          enqueueSnackbar(message, { variant: 'error' });
          set({ sendingEmail: false });
        }
      },

      sendFormToCandidate: async (data) => {
        set({ sendingForm: true });
        try {
          await candidatesApi.sendFormToCandidate(data);
          enqueueSnackbar('Formulaire envoyé avec succès', { variant: 'success' });
          set({ sendingForm: false });
        } catch (error: any) {
          const backendMessage = error?.message ?? error?.response?.data?.message;
          const message = backendMessage || "Erreur lors de l'envoi du formulaire";
          enqueueSnackbar(message, { variant: 'error' });
          set({ sendingForm: false });
          throw error;
        }
      },

      fetchStatistics: async () => {
        try {
          const statistics = await candidatesApi.getCandidateStatistics();
          set({ statistics });
        } catch (error) {}
      },

      fetchDepartments: async () => {
        set({ departmentsLoading: true });
        try {
          const response = await candidatesApi.getDepartments();
          set({ departments: response, departmentsLoading: false });
        } catch (error) {
          enqueueSnackbar('Erreur lors du chargement des départements', { variant: 'error' });
          set({ departments: [], departmentsLoading: false });
        }
      },

      bulkUpdateStatus: async (candidateIds, status, reason) => {
        set({ updating: true });
        try {
          await candidatesApi.bulkUpdateStatus(candidateIds, status, reason);
          enqueueSnackbar('Statuts mis à jour en masse avec succès', { variant: 'success' });

          const { currentStatus, currentType, currentPage, pageSize } = get();
          if (currentStatus) {
            await get().fetchCandidatesByStatus(
              currentStatus,
              currentType || undefined,
              currentPage,
              pageSize
            );
          } else {
            await get().fetchCandidates(currentPage, pageSize);
          }

          set({ updating: false });
        } catch (error: any) {
          const message = error.response?.data?.message || 'Erreur lors de la mise à jour en masse';
          enqueueSnackbar(message, { variant: 'error' });
          set({ updating: false });
        }
      },

      bulkSendEmail: async (candidateIds, subject, message) => {
        set({ sendingEmail: true });
        try {
          await candidatesApi.bulkSendEmail(candidateIds, subject, message);
          enqueueSnackbar('Emails envoyés en masse avec succès', { variant: 'success' });
          set({ sendingEmail: false });
        } catch (error: any) {
          const message = error.response?.data?.message || "Erreur lors de l'envoi en masse";
          enqueueSnackbar(message, { variant: 'error' });
          set({ sendingEmail: false });
        }
      },

      exportCandidates: async (exportData: ExportCandidateRequest) => {
        set({ exporting: true, exportProgress: 0 });
        try {
          const response: ExportCandidateResponse =
            await candidatesApi.exportCandidates(exportData);
          enqueueSnackbar('Export démarré avec succès', { variant: 'success' });
          set({ exporting: false, exportProgress: 100 });

          return response.exportPath;
        } catch (error: any) {
          const message = error.response?.data?.message || "Erreur lors du démarrage de l'export";
          enqueueSnackbar(message, { variant: 'error' });
          set({ exporting: false, exportProgress: 0 });
          return null;
        }
      },

      downloadExportFile: async (filePath: string) => {
        try {
          const blob = await candidatesApi.downloadExportFile(filePath);

          const url = window.URL.createObjectURL(blob);
          const link = document.createElement('a');
          link.href = url;

          const fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
          link.download = fileName;

          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);

          window.URL.revokeObjectURL(url);
          enqueueSnackbar('Fichier exporté téléchargé avec succès', { variant: 'success' });
        } catch (error: any) {
          const message =
            error.response?.data?.message || 'Erreur lors du téléchargement du fichier';
          enqueueSnackbar(message, { variant: 'error' });
        }
      },

      setCurrentStatus: (status) => set({ currentStatus: status }),
      setCurrentType: (type) => set({ currentType: type }),
      setSearchQuery: (query) => set({ searchQuery: query }),
      setPage: (page) => set({ currentPage: page }),
      setPageSize: (size) => set({ pageSize: size }),

      clearFilters: () =>
        set({
          currentStatus: null,
          currentType: 'DRIVER',
          searchQuery: '',
          currentPage: 0,
        }),

      resetState: () => set(initialState),
    }),
    {
      name: 'candidates-store',
    }
  )
);
