import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { ExcursionSearchParams, ExtendedFlightSearchResponseItem, Filter, FlyInType, SortByType } from '../types';
import {
  BookingPackage,
  BookingPackageItem,
  BookingPriceDetails,
  ClientPortalItinerary,
  PackagingAccommodationResponse,
  PackagingEntry,
  PackagingFlightResponse
} from '@qite/tide-client/build/types';

export interface SearchResultsState {
  results: BookingPackageItem[];
  filteredResults: BookingPackageItem[];
  selectedSearchResult: BookingPackageItem | null;

  packagingAccoResults: PackagingAccommodationResponse[];
  filteredPackagingAccoResults: PackagingAccommodationResponse[];
  packagingAccoSearchDetails: PackagingAccommodationResponse[];
  selectedPackagingAccoResultCode: string | null;

  packagingFlightResults: PackagingFlightResponse[];
  filteredPackagingFlightResults: PackagingFlightResponse[];
  selectedPackagingFlight: PackagingFlightResponse | null;
  selectedOutwardKey: string | null;
  selectedReturnKey: string | null;

  selectedFlight: ExtendedFlightSearchResponseItem | null;
  selectedFlightDetails: ExtendedFlightSearchResponseItem | null;

  bookingPackageDetails: BookingPackage | null;
  priceDetails: BookingPriceDetails | null;

  isLoading: boolean;
  flightsLoading: boolean;

  selectedSortType: SortByType | null;
  selectedFlightSortType: SortByType | null;
  filters: Filter[];
  initialFilters: Filter[];
  flightFilters: Filter[];
  initialFlightFilters: Filter[];

  activeTab: string | null;
  currentPage: number;

  transactionId: string | null;

  flyInIsOpen: boolean;
  flyInType: FlyInType | null;

  itinerary: ClientPortalItinerary | null;
  editablePackagingEntry: PackagingEntry | null;

  excursionSearchParams: ExcursionSearchParams | null;
  selectedExcursionSearchResult: PackagingAccommodationResponse | null;
  confirmedExcursionsByDay: Record<string, PackagingAccommodationResponse[]>;

  bookPackagingEntry: boolean;
  currentStep: number;
  bookingNumber?: string;
}

const initialState: SearchResultsState = {
  results: [],
  filteredResults: [],
  selectedSearchResult: null,

  packagingAccoResults: [],
  filteredPackagingAccoResults: [],
  packagingAccoSearchDetails: [],
  selectedPackagingAccoResultCode: null,

  packagingFlightResults: [],
  filteredPackagingFlightResults: [],
  selectedPackagingFlight: null,
  selectedOutwardKey: null,
  selectedReturnKey: null,

  selectedFlight: null,
  selectedFlightDetails: null,

  bookingPackageDetails: null,
  priceDetails: null,

  isLoading: false,
  flightsLoading: false,

  selectedSortType: null,
  selectedFlightSortType: null,
  initialFilters: [],
  filters: [],
  initialFlightFilters: [],
  flightFilters: [],

  activeTab: 'compact',
  currentPage: 1,

  transactionId: null,

  flyInIsOpen: false,
  flyInType: null,

  editablePackagingEntry: null,
  itinerary: null,

  excursionSearchParams: null,
  selectedExcursionSearchResult: null,
  confirmedExcursionsByDay: {},

  bookPackagingEntry: false,
  currentStep: 0,
  bookingNumber: undefined
};

const searchResultsSlice = createSlice({
  name: 'searchResults',
  initialState,
  reducers: {
    setResults(state, action: PayloadAction<BookingPackageItem[]>) {
      state.results = action.payload;
    },
    setFilteredResults(state, action: PayloadAction<BookingPackageItem[]>) {
      state.filteredResults = action.payload;
    },
    setSelectedSearchResult(state, action: PayloadAction<BookingPackageItem | null>) {
      state.selectedSearchResult = action.payload;
    },
    setPackagingAccoResults(state, action: PayloadAction<PackagingAccommodationResponse[]>) {
      state.packagingAccoResults = action.payload;
    },
    setFilteredPackagingAccoResults(state, action: PayloadAction<PackagingAccommodationResponse[]>) {
      state.filteredPackagingAccoResults = action.payload;
    },
    setPackagingAccoSearchDetails(state, action: PayloadAction<PackagingAccommodationResponse[]>) {
      state.packagingAccoSearchDetails = action.payload;
    },
    setSelectedPackagingAccoResult(state, action: PayloadAction<string | null>) {
      state.selectedPackagingAccoResultCode = action.payload;
    },
    setPackagingFlightResults(state, action: PayloadAction<PackagingFlightResponse[]>) {
      state.packagingFlightResults = action.payload;
    },
    setFilteredPackagingFlightResults(state, action: PayloadAction<PackagingFlightResponse[]>) {
      state.filteredPackagingFlightResults = action.payload;
    },
    setSelectedPackagingFlight(state, action: PayloadAction<PackagingFlightResponse | null>) {
      state.selectedPackagingFlight = action.payload;
    },
    setSelectedFlight(state, action: PayloadAction<ExtendedFlightSearchResponseItem | null>) {
      state.selectedFlight = action.payload;
    },
    setSelectedFlightDetails(state, action: PayloadAction<ExtendedFlightSearchResponseItem | null>) {
      state.selectedFlightDetails = action.payload;
    },
    setBookingPackageDetails(state, action: PayloadAction<{ details: BookingPackage }>) {
      state.bookingPackageDetails = action.payload.details;
    },
    selectFlight(state, action: PayloadAction<{ flightOptionId: string; isDeparture: boolean }>) {
      if (!state.bookingPackageDetails) return;

      const { flightOptionId, isDeparture } = action.payload;

      const flightKey = isDeparture ? 'outwardFlights' : 'returnFlights';

      state.bookingPackageDetails[flightKey] = state.bookingPackageDetails[flightKey].map((flight) => ({
        ...flight,
        isSelected: flight.flightOptionId === flightOptionId
      }));
    },
    setIsLoading(state, action: PayloadAction<boolean>) {
      state.isLoading = action.payload;
    },
    setFlightsLoading(state, action: PayloadAction<boolean>) {
      state.flightsLoading = action.payload;
    },
    setInitialFilters(state, action: PayloadAction<Filter[]>) {
      state.initialFilters = action.payload;
    },
    setFilters(state, action: PayloadAction<Filter[]>) {
      const updatedFilters = action.payload;

      updatedFilters.forEach((updatedFilter) => {
        const existingIndex = state.filters.findIndex((f) => f.property === updatedFilter.property);
        if (existingIndex !== -1) {
          state.filters[existingIndex] = updatedFilter;
        } else {
          state.filters.push(updatedFilter); // Optional: Add new filters if not present
        }
      });
    },
    resetFilters(state, action: PayloadAction<Filter[]>) {
      state.filters = action.payload;
    },
    setInitialFlightFilters(state, action: PayloadAction<Filter[]>) {
      state.initialFlightFilters = action.payload;
    },
    setFlightFilters(state, action: PayloadAction<Filter[]>) {
      const updatedFilters = action.payload;

      updatedFilters.forEach((updatedFilter) => {
        const existingIndex = state.flightFilters.findIndex((f) => f.property === updatedFilter.property);
        if (existingIndex !== -1) {
          state.flightFilters[existingIndex] = updatedFilter;
        } else {
          state.flightFilters.push(updatedFilter); // Optional: Add new filters if not present
        }
      });
    },
    resetFlightFilters(state, action: PayloadAction<Filter[]>) {
      state.flightFilters = action.payload;
    },
    setSortType(state, action: PayloadAction<SortByType | null>) {
      state.selectedSortType = action.payload;
    },
    setFlightSortType(state, action: PayloadAction<SortByType | null>) {
      state.selectedFlightSortType = action.payload;
    },
    setActiveTab(state, action: PayloadAction<string | null>) {
      state.activeTab = action.payload;
    },
    setCurrentPage(state, action: PayloadAction<number>) {
      state.currentPage = action.payload;
    },
    resetSearchState(state) {
      state.results = [];
      state.isLoading = false;
      state.filters = [];
      state.selectedSortType = null;
      state.activeTab = 'compact';
      state.currentPage = 1;
    },
    setFlyInIsOpen(state, action: PayloadAction<boolean>) {
      state.flyInIsOpen = action.payload;
    },
    setEditablePackagingEntry(state, action: PayloadAction<PackagingEntry | null>) {
      state.editablePackagingEntry = action.payload;
    },
    setTransactionId(state, action: PayloadAction<string | null>) {
      state.transactionId = action.payload;
    },
    setFlyInType(state, action: PayloadAction<FlyInType | null>) {
      state.flyInType = action.payload;
    },
    setPriceDetails(state, action: PayloadAction<BookingPriceDetails | null>) {
      state.priceDetails = action.payload;
    },
    setItinerary(state, action: PayloadAction<ClientPortalItinerary | null>) {
      state.itinerary = action.payload;
    },
    setSelectedOutwardKey: (state, action: PayloadAction<string | null>) => {
      state.selectedOutwardKey = action.payload;
    },
    setSelectedReturnKey: (state, action: PayloadAction<string | null>) => {
      state.selectedReturnKey = action.payload;
    },
    resetFlightSelection: (state) => {
      state.selectedOutwardKey = null;
      state.selectedReturnKey = null;
    },
    setExcursionSearchParams(state, action: PayloadAction<ExcursionSearchParams>) {
      state.excursionSearchParams = action.payload;
    },
    setSelectedExcursionSearchResult(state, action: PayloadAction<PackagingAccommodationResponse | null>) {
      state.selectedExcursionSearchResult = action.payload;
    },
    confirmExcursionForDay: (state, action: PayloadAction<{ dayKey: string; excursion: PackagingAccommodationResponse }>) => {
      const { dayKey, excursion } = action.payload;

      const existingForDay = state.confirmedExcursionsByDay[dayKey] ?? [];

      const existingIndex = existingForDay.findIndex((item) => item.code === excursion.code);

      if (existingIndex >= 0) {
        // replace existing confirmed version of same excursion
        existingForDay[existingIndex] = excursion;
      } else {
        existingForDay.push(excursion);
      }

      state.confirmedExcursionsByDay[dayKey] = existingForDay;
    },
    removeConfirmedExcursionForDay: (state, action: PayloadAction<{ dayKey: string; excursionCode: string }>) => {
      const { dayKey, excursionCode } = action.payload;

      state.confirmedExcursionsByDay[dayKey] = (state.confirmedExcursionsByDay[dayKey] ?? []).filter((item) => item.code !== excursionCode);
    },
    clearConfirmedExcursionsForDay: (state, action: PayloadAction<{ dayKey: string }>) => {
      delete state.confirmedExcursionsByDay[action.payload.dayKey];
    },
    setBookPackagingEntry(state, action: PayloadAction<boolean>) {
      state.bookPackagingEntry = action.payload;
    },
    setCurrentStep(state, action: PayloadAction<number>) {
      state.currentStep = action.payload;
    },
    setBookingNumber(state, action: PayloadAction<string>) {
      state.bookingNumber = action.payload;
    }
  }
});

export const {
  setResults,
  setFilteredResults,
  setSelectedSearchResult,
  setPackagingAccoResults,
  setFilteredPackagingAccoResults,
  setFilteredPackagingFlightResults,
  setPackagingAccoSearchDetails,
  setSelectedPackagingAccoResult,
  setPackagingFlightResults,
  setSelectedPackagingFlight,
  setSelectedFlight,
  setSelectedFlightDetails,
  setBookingPackageDetails,
  selectFlight,
  setIsLoading,
  setFlightsLoading,
  setInitialFilters,
  setFilters,
  resetFilters,
  setInitialFlightFilters,
  setFlightFilters,
  resetFlightFilters,
  setSortType,
  setFlightSortType,
  setActiveTab,
  setCurrentPage,
  resetSearchState,
  setFlyInIsOpen,
  setEditablePackagingEntry,
  setTransactionId,
  setFlyInType,
  setPriceDetails,
  setItinerary,
  setSelectedOutwardKey,
  setSelectedReturnKey,
  resetFlightSelection,
  setExcursionSearchParams,
  setSelectedExcursionSearchResult,
  confirmExcursionForDay,
  removeConfirmedExcursionForDay,
  clearConfirmedExcursionsForDay,
  setBookPackagingEntry,
  setCurrentStep,
  setBookingNumber
} = searchResultsSlice.actions;

export default searchResultsSlice.reducer;
