import { create } from 'zustand';
import axiosInstance from '@/utils/axios';


import { ITrajet, IAddPoint, IAddPointRequest } from '@/shared/types/trajet';
import { RouteMarker } from '@/shared/types/Maps';
import { EtatTrajet, TypeTrajet, BinaryQuestion } from '@/shared/types/trajet';
import { Sens } from '@/shared/types/circuit';
import type { ISuiviTrajet } from '@/shared/types/trajet';
import { _trajets } from '@/shared/_mock/_trajets';
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
import { endpoints_Trajet } from '../endpoints/trajet';

// Extend dayjs with isBetween plugin
dayjs.extend(isBetween);

type TrajetPageFilterParams = {
  id?: string;
  dateTrip?: string; 
  days?: string;
  sens?: 'DEPARTURE' | 'RETURN';
  rotation?: boolean;
  nbrUsagers?: number;
  nbrEtablissements?: number;
  tripState?: 'CONTROLE' | 'MODIFIE' | 'NON CONTROLE';
  driverName?: string;
  vehicleName?: string;
  hasTolls?: boolean;
  companyName?: string;
  clientName?: string;
  tripType?: 'NORMAL' | 'PERSONALIZED';
  sortBy?: string;
  sortDirection?: 'asc' | 'desc';
  page?: number;
  size?: number;
};

const transformApiDataToFrontend = (apiData: any): ITrajet => {
  let etatValue = EtatTrajet.NonControle;
  if (apiData.tripState === 'CONTROLE') {
    etatValue = EtatTrajet.Controle;
  } else if (apiData.tripState === 'MODIFIE') {
    etatValue = EtatTrajet.Modifier;
  } else if (apiData.tripState === 'NON CONTROLE') {
    etatValue = EtatTrajet.NonControle;
  }

  let rotationValue = BinaryQuestion.Non;
  if (apiData.rotation === true || apiData.rotation === 'oui' || apiData.rotation === BinaryQuestion.Oui) {
    rotationValue = BinaryQuestion.Oui;
  }

  
  let peagesValue = BinaryQuestion.Non;
  if (apiData.hasTolls === true || 
      apiData.peages === BinaryQuestion.Oui || 
      apiData.peages === 'oui') {
    peagesValue = BinaryQuestion.Oui;
  }
  let typeTrajetValue = TypeTrajet.Normal; // default value
  if (apiData.tripType === 'PERSONNALISE' || apiData.tripType === 'PERSONALIZED') {
    typeTrajetValue = TypeTrajet.personnalise;
  } else if (apiData.tripType === 'NORMAL') {
    typeTrajetValue = TypeTrajet.Normal;
  }

 

  let joursValue = undefined;
  if (apiData.weekType) {
    joursValue = {
      pair:
        apiData.weekType === 'EVEN'
          ? {
              lundi: { matin: true, soir: true },
              mardi: { matin: true, soir: true },
              mercredi: { matin: true, soir: true },
              jeudi: { matin: true, soir: true },
              vendredi: { matin: true, soir: true },
              samedi: { matin: false, soir: false },
              dimanche: { matin: false, soir: false },
            }
          : {
              lundi: { matin: false, soir: false },
              mardi: { matin: false, soir: false },
              mercredi: { matin: false, soir: false },
              jeudi: { matin: false, soir: false },
              vendredi: { matin: false, soir: false },
              samedi: { matin: false, soir: false },
              dimanche: { matin: false, soir: false },
            },
      impair:
        apiData.weekType === 'ODD'
          ? {
              lundi: { matin: true, soir: true },
              mardi: { matin: true, soir: true },
              mercredi: { matin: true, soir: true },
              jeudi: { matin: true, soir: true },
              vendredi: { matin: true, soir: true },
              samedi: { matin: false, soir: false },
              dimanche: { matin: false, soir: false },
            }
          : {
              lundi: { matin: false, soir: false },
              mardi: { matin: false, soir: false },
              mercredi: { matin: false, soir: false },
              jeudi: { matin: false, soir: false },
              vendredi: { matin: false, soir: false },
              samedi: { matin: false, soir: false },
              dimanche: { matin: false, soir: false },
            },
    };
  }

  return {
    id: apiData.id,
    intitule: apiData.title || apiData.id,
    circuitAvenant: apiData.circuitId || '',
    dateDebut: apiData.dateTrip || apiData.avenantDate || '',
    etat: etatValue,
    typeTrajet: typeTrajetValue,
    chauffeur: apiData.chauffeur || '',
    vehicule: apiData.vehicule || apiData.vehicleName || '',
    peages: peagesValue,
    sensAR: apiData.sens === 'DEPARTURE' ? Sens.Aller : Sens.Retour,
    rotation: rotationValue,
    nombreUsagers: apiData.nbrUsagers || 0,
    nombreEtablissements: apiData.nbrEtablissements || 0,
    societe: apiData.companyName || apiData.societe || '',
    client: apiData.clientName || apiData.client || '',
    isActive: true,
    days: apiData.days || '',
    origine: apiData.origin || '',
    destination: apiData.destination || '',
    distanceKm: apiData.distanceKm || 0,
    duree: apiData.duration || '',
    datePersonnalisation: apiData.customizedDate || '',
    observationPersonnalisation: apiData.customizationNote || '',
    observationFeuilleRoute: apiData.routeSheetNote || '',
    jours: joursValue,
    dateTrip: apiData.dateTrajet || '',
    statut: apiData.statut || apiData.sens || '',
    etatConfirmation: apiData.etatConfirmation || '',
    etatControle: apiData.etatControle || '',
    etatVehicule: apiData.etatVehicule || '',
  };
};

export interface TripPointDto {
  id?: string;
  tripId: string;
  title: string;
  label: string;
  passengerId?: number;
  passengerName?: string;
  usage: 'START' | 'STOP' | 'END'; 
  address: {
    fullAddress: string;
  };
  latitude: number;
  longitude: number;
  coordinates: [number, number];
  sequenceOrder: number;
  arrivalTime?: string;
  departureTime?: string;
  distanceFromPreviousPoint?: number;
  timeFromPreviousPoint?: number;
  isTemporaryForUser?: boolean;
}

type TrajetStore = {
  error: string | null;
  loading: boolean;
  trajets: ITrajet[];
  totalElements: number;
  fetchTrajets: (params: TrajetPageFilterParams) => Promise<void>;
  trajetById: ITrajet | null;
  getTrajetById: (trajetId: string) => Promise<ITrajet | null>;
  createTrajet: (trajet: ITrajet) => Promise<void>;
  updateTrajet: (trajetId: string, trajet: ITrajet) => Promise<void>;
  toggleTrajetActivation: (trajetId: string, isActive: boolean) => Promise<void>;
  updateTrajetStatus: (trajetId: string, field: string, value: string) => Promise<ITrajet | null>;
  suiviTrajets: ISuiviTrajet[];
  fetchSuiviTrajets: (trajetId: string) => Promise<void>;
  updateSuiviTrajets: (trajetId: string, suiviTrajets: ISuiviTrajet[]) => Promise<void>;
  exportTrajetDataInCsv: (params: TrajetPageFilterParams) => Promise<void>;
  exportTrajetDataInPdf: (params: TrajetPageFilterParams) => Promise<void>;
  tripPoints: TripPointDto[];
  getTripPoints: (tripId: string) => Promise<void>;
  addTripPoint: (point: TripPointDto) => Promise<void>;
  updateTripPoint: (pointId: string, point: TripPointDto) => Promise<void>;
  deleteTripPoint: (pointId: string) => Promise<void>;
  reorderTripPoints: (tripId: string, pointIds: string[]) => Promise<void>;
  
};

export const useTrajetStore = create<TrajetStore>((set, get) => ({
  error: null,
  loading: false,
  trajets: [],
  totalElements: 0,
  suiviTrajets: [],
  trajetById: null,
  tripPoints: [],

  fetchTrajets: async (params: TrajetPageFilterParams) => {
    set({ loading: true, error: null });
    try {
      
      const filterParams: Record<string, any> = {
        id: params.id,
        dateTrip: params.dateTrip
          ? dayjs(params.dateTrip).format('YYYY-MM-DD')
          : undefined,
        days: params.days,
        sens: params.sens,
        rotation: params.rotation,
        nbrUsagers: typeof params.nbrUsagers === 'number' ? params.nbrUsagers : undefined,
        nbrEtablissements: typeof params.nbrEtablissements === 'number' ? params.nbrEtablissements : undefined,
        tripState: params.tripState,
        driverName: params.driverName,
        vehicleName: params.vehicleName,
        hasTolls: params.hasTolls,
        companyName: params.companyName,
        clientName: params.clientName,
        tripType: params.tripType
      };


      Object.keys(filterParams).forEach(key => {
        if (filterParams[key] === undefined || filterParams[key] === null || filterParams[key] === '') {
          delete filterParams[key];
        }
      });

      

      const paginationParams = {
        page: params.page || 0,
        size: params.size || 10,
        sortBy: params.sortBy || 'id',
        sortDir: params.sortDirection || 'asc'
      };

      // For mock data, filter directly if using mock data
      if (process.env.NEXT_PUBLIC_USE_MOCK_DATA === 'true') {
        const content = _trajets.filter((trajet: ITrajet) => {
          // Match all filter conditions
          if (filterParams.startDate && filterParams.endDate) {
            // Convert mock data date to comparable format
            const trajetDate = dayjs(trajet.dateDebut).startOf('day');
            const filterStartDate = dayjs(filterParams.startDate).startOf('day');
            const filterEndDate = dayjs(filterParams.endDate).endOf('day');
            
            // Check if trajet date falls within the filter range
            if (!trajetDate.isBetween(filterStartDate, filterEndDate, 'day', '[]')) {
              return false;
            }
          }
          if (filterParams.companyName && 
            trajet.societe?.toLowerCase() !== filterParams.companyName.toLowerCase()) {
          return false;
        }
        
        // Client name filter
        if (filterParams.clientName && 
            trajet.client?.toLowerCase() !== filterParams.clientName.toLowerCase()) {
          return false;
        }
          // Add other filter conditions as needed
          return true;
        });

        const start = paginationParams.page * paginationParams.size;
        const end = start + paginationParams.size;
        const paginatedContent = content.slice(start, end);

        set({
          trajets: paginatedContent,
          totalElements: content.length,
          loading: false,
        });
        return;
      }

      // For backend API call
      const response = await axiosInstance.post(
        endpoints_Trajet.Trajet.filterTrajets, 
        filterParams,
        { params: paginationParams }
      );

      

      const content = response.data.content || response.data;
      const totalElements = response.data.totalElements || content.length;
      const transformedData = content.map(transformApiDataToFrontend);

      set({
        trajets: transformedData,
        totalElements: totalElements,
        loading: false,
      });
    } catch (error: any) {
      console.error('Error fetching trajets:', error);
      set({ error: error.message || 'Failed to fetch trajets', loading: false });
    }
  },

  getTrajetById: async (id: string) => {
    try {
      const response = await axiosInstance.get(`/api/circuit/trips/${id}`);
      return response.data;
    } catch (error) {
    
      throw error;
    }
  },

  createTrajet: async (trajet) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.post(endpoints_Trajet.Trajet.createTrajet, trajet);
      const transformedData = transformApiDataToFrontend(response.data);

      set((state) => ({
        trajets: [...state.trajets, transformedData],
        loading: false,
      }));
    } catch (error: any) {
      set({ error: error.message || 'Failed to create trajet', loading: false });
    }
  },

  updateTrajet: async (trajetId, trajet) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.put(
        endpoints_Trajet.Trajet.updateTrajet(trajetId),
        trajet
      );
      const transformedData = transformApiDataToFrontend(response.data);

      set((state) => ({
        trajets: state.trajets.map((t) => (t.id === trajetId ? transformedData : t)),
        loading: false,
      }));
    } catch (error: any) {
      set({ error: error.message || 'Failed to update trajet', loading: false });
    }
  },

  toggleTrajetActivation: async (trajetId, isActive) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.post(
        endpoints_Trajet.Trajet.toggleTrajetActivation(trajetId, isActive)
      );
      const transformedData = transformApiDataToFrontend(response.data);

      set((state) => ({
        trajets: state.trajets.map((t) => (t.id === trajetId ? transformedData : t)),
        loading: false,
      }));
    } catch (error: any) {
      set({ error: error.message || 'Failed to toggle trajet activation', loading: false });
    }
  },

  updateTrajetStatus: async (id: string, field: string, value: string) => {
    set({ loading: true });
    try {
      let backendField = field;
      let backendValue = value;

      

      switch (field) {
        case 'typeTrajet':
          backendField = 'tripType';
          backendValue = value === TypeTrajet.Normal ? 'NORMAL' : 'PERSONALIZED';
  
          break;

        case 'etat':
          backendField = 'tripState';
          backendValue = value === EtatTrajet.Controle ? 'CONTROLE' :
                        value === EtatTrajet.Modifier ? 'MODIFIE' :
                        'NON_CONTROLE';
          break;

        case 'sensAR':
          backendField = 'sens';
          backendValue = value === Sens.Aller ? 'DEPARTURE' : 'RETURN';
          break;

        case 'rotation':
          backendField = 'rotation';
          backendValue = value === BinaryQuestion.Oui ? 'oui' : 'non';
          break;

        case 'peages':
          backendField = 'hasTolls';
          backendValue = value === BinaryQuestion.Oui ? 'oui' : 'non';
          break;

        default:
          break;
      }

      

      const response = await axiosInstance.post(
        `${endpoints_Trajet.Trajet.updateTrajetStatus(id, backendField)}`,
        { value: backendValue },
        {
          headers: {
            'Content-Type': 'application/json',
          },
        }
      );

      

      
      const updatedTrajet = transformApiDataToFrontend(response.data);
      

      // Update the trajet in the store with a merge
      set((state) => ({
        trajets: state.trajets.map((trajet) => 
          trajet.id === id ? { ...trajet, ...updatedTrajet } : trajet
        ),
        loading: false,
      }));

      return updatedTrajet;
    } catch (error: any) {
      console.error('Error updating trajet status:', error);
      set({ error: error.message, loading: false });
      throw error;
    }
  },

  fetchSuiviTrajets: async (trajetId: string) => {
    try {
      
      const response = await axiosInstance.get(`/api/circuit/trip-points/trip/${trajetId}/suivi`);
      return response.data;
    } catch (error) {
      console.error('API Error:', error);
      throw error;
    }
  },

  updateSuiviTrajets: async (trajetId: string, suiviTrajets: ISuiviTrajet[]) => {
    set({ loading: true, error: null });
    try {
      
      const response = await axiosInstance.put(
        `/api/circuit/trip-points/trip/${trajetId}/suivi/reorder`,
        suiviTrajets
      );
      
      set({
        suiviTrajets: response.data,
        loading: false
      });
    } catch (error) {
      
      set({ 
        error: 'Failed to update suivi trajets', 
        loading: false 
      });
    }
  },

  exportTrajetDataInCsv: async (params) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(endpoints_Trajet.Trajet.exportTrajetDataInCsv, {
        params,
        responseType: 'blob',
      });

      const url = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement('a');
      link.href = url;
      link.setAttribute('download', 'trajets.csv');
      document.body.appendChild(link);
      link.click();
      link.remove();

      set({ loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to export trajets in CSV', loading: false });
    }
  },

  exportTrajetDataInPdf: async (params) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(endpoints_Trajet.Trajet.exportTrajetDataInPdf, {
        params,
        responseType: 'blob',
      });
      const url = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement('a');
      link.href = url;
      link.setAttribute('download', 'trajets.pdf');
      document.body.appendChild(link);
      link.click();
      link.remove();

      set({ loading: false });
    } catch (error: any) {
      set({ error: error.message || 'Failed to export trajets in PDF', loading: false });
    }
  },

  getTripPoints: async (tripId: string) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.get(
        endpoints_Trajet.Trajet.TripPoint.getPoints(tripId)
      );
      
      set({
        tripPoints: response.data,
        loading: false,
      });
    } catch (error: any) {
      set({ 
        error: error.message || 'Failed to fetch trip points',
        loading: false 
      });
    }
  },

  addTripPoint: async (point: TripPointDto) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.post(
        endpoints_Trajet.Trajet.TripPoint.addPoint,
        point
      );
      
      set((state) => ({
        tripPoints: [...state.tripPoints, response.data],
        loading: false,
      }));
    } catch (error: any) {
      set({ 
        error: error.message || 'Failed to add trip point',
        loading: false 
      });
    }
  },

  updateTripPoint: async (pointId: string, point: TripPointDto) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.put(
        endpoints_Trajet.Trajet.TripPoint.updatePoint(pointId),
        point
      );
      
      set((state) => ({
        tripPoints: state.tripPoints.map((p) => 
          p.id === pointId ? response.data : p
        ),
        loading: false,
      }));
    } catch (error: any) {
      set({ 
        error: error.message || 'Failed to update trip point',
        loading: false 
      });
    }
  },

  deleteTripPoint: async (pointId: string) => {
    set({ loading: true, error: null });
    try {
      await axiosInstance.delete(
        endpoints_Trajet.Trajet.TripPoint.deletePoint(pointId)
      );
      
      set((state) => ({
        tripPoints: state.tripPoints.filter((p) => p.id !== pointId),
        loading: false,
      }));
    } catch (error: any) {
      set({ 
        error: error.message || 'Failed to delete trip point',
        loading: false 
      });
    }
  },

  reorderTripPoints: async (tripId: string, pointIds: string[]) => {
    set({ loading: true, error: null });
    try {
      const response = await axiosInstance.post(
        endpoints_Trajet.Trajet.TripPoint.reorderPoints(tripId),
        pointIds
      );
      
      set({
        tripPoints: response.data,
        loading: false,
      });
    } catch (error: any) {
      set({ 
        error: error.message || 'Failed to reorder trip points',
        loading: false 
      });
    }
  },
}));
