import { BookingPackageItem, PackagingAccommodationResponse, PackagingFlightResponse } from '@qite/tide-client';
import { Filter, SortByType, TideTag } from '../types';
import { filter, flatMap, orderBy } from 'lodash';
import { getArrivalSegment, getDepartureRangeName, getDepartureSegment, getNumberOfStops } from './flight-utils';
import { DepartureRange } from '../../shared/types';
import { durationInTicksInMinutes, rangeFromDateTimeInMinutes } from '../../shared/utils/localization-util';

export const enrichFiltersWithResults = (results: BookingPackageItem[], filters: Filter[] | undefined, tags: TideTag[]): Filter[] => {
  if (!results || results.length === 0 || !filters) {
    return filters ?? [];
  }

  return filters.map((filter) => {
    let updatedFilter = { ...filter };

    if (filter.property === 'price' && (filter.min == null || filter.max == null)) {
      const prices = results.map((r) => r.price ?? 0).filter((p) => p > 0);
      if (prices.length > 0) {
        updatedFilter.min = Math.floor(Math.min(...prices));
        updatedFilter.max = Math.ceil(Math.max(...prices));
      }
    }

    if (filter.property === 'accommodation') {
      const map = new Map<string, { name?: string; code: string }>();

      results.forEach((r) => {
        if (r.accommodationCode) {
          map.set(r.accommodationCode, {
            name: r.accommodationName,
            code: r.accommodationCode
          });
        }
      });

      updatedFilter.options = Array.from(map.values()).map((accommodation) => ({
        label: accommodation.name ?? accommodation.code,
        value: accommodation.code,
        isChecked: false
      }));
    }

    if (filter.property === 'regime') {
      const map = new Map<string, { name?: string; code: string }>();

      results.forEach((r) => {
        if (r.regimeCode) {
          map.set(r.regimeCode, {
            name: r.regimeName,
            code: r.regimeCode
          });
        }
      });

      updatedFilter.options = Array.from(map.values()).map((regime) => ({
        label: regime.name ?? regime.code,
        value: regime.code,
        isChecked: false
      }));
    }

    if (filter.property === 'theme') {
      const map = new Map<number, { name: string; id: number }>();

      results.forEach((r) => {
        r.tagIds?.forEach((tagId) => {
          const tag = tags.find((t) => t.id === tagId);
          if (tag && tag.id != null && tag.name != null) {
            map.set(tag.id, { name: tag.name, id: tag.id });
          }
        });
      });

      updatedFilter.options = Array.from(map.values()).map((theme) => ({
        label: theme.name,
        value: theme.id,
        isChecked: false
      }));
    }

    return updatedFilter;
  });
};

export const enrichFiltersWithPackageAccoResults = (results: PackagingAccommodationResponse[], tags: TideTag[]): Filter[] => {
  const filters: Filter[] = [];
  if (!results || results.length === 0) {
    return filters;
  }

  const regimeFilter: Filter = {
    property: 'regime',
    label: 'Regime',
    type: 'checkbox',
    options: [],
    isFrontendFilter: true
  };
  const map = new Map<string, { name?: string; code: string }>();

  results.forEach((r) => {
    const rooms = flatMap(r.rooms);
    if (rooms) {
      rooms.map((room) => {
        room.options.map((option) => {
          if (option.regimeCode) {
            map.set(option.regimeCode, {
              name: option.regimeName,
              code: option.regimeCode
            });
          }
        });
      });
    }
  });

  regimeFilter.options = Array.from(map.values()).map((regime) => ({
    label: regime.name ?? regime.code,
    value: regime.code,
    isChecked: false
  }));
  filters.push(regimeFilter);

  const priceFilter: Filter = {
    property: 'price',
    label: 'Prijs',
    type: 'slider',
    isFrontendFilter: true
  };
  const prices = results.map((r) => r.price ?? 0).filter((p) => p > 0);
  priceFilter.min = Math.floor(Math.min(...prices));
  priceFilter.max = Math.ceil(Math.max(...prices));

  filters.push(priceFilter);

  const starsFilter: Filter = {
    property: 'rating',
    label: 'Stars',
    type: 'star-rating',
    options: [],
    isFrontendFilter: true
  };
  const ratingMap = new Map<string, { name?: string; value: number }>();

  results.forEach((r) => {
    const stars = r.stars;
    if (stars) {
      ratingMap.set(stars.toString(), {
        name: stars.toString(),
        value: stars
      });
    }
  });

  starsFilter.options = Array.from(ratingMap.values()).map((rating) => ({
    label: rating.name ?? rating.value.toString(),
    value: rating.value,
    isChecked: false
  }));

  filters.push(starsFilter);

  return filters;
};

export const enrichFiltersWithPackageFlightResults = (results: PackagingFlightResponse[], tags: TideTag[], translations: any): Filter[] => {
  const filters: Filter[] = [];
  if (!results || results.length === 0) {
    return filters;
  }

  // Airlines
  const airlinesFilter: Filter = {
    label: 'Airlines',
    property: 'airline',
    type: 'checkbox',
    isFrontendFilter: true,
    options: []
  };
  const airlinesFilterMap = new Map<string, { name?: string; code: string }>();

  results.map((r) => {
    const airlineCode = r.airlineCode;
    const airlineName = r.airlineName;
    if (airlineCode && airlineName) {
      airlinesFilterMap.set(airlineCode, {
        name: airlineName,
        code: airlineCode
      });
    }
  });

  airlinesFilter.options = Array.from(airlinesFilterMap.values()).map((airline) => ({
    label: airline.name ?? airline.code,
    value: airline.code,
    isChecked: false
  }));

  filters.push(airlinesFilter);

  // Number of stops
  const stopsFilter: Filter = {
    label: 'Number of Stops',
    property: 'numberOfStops',
    type: 'checkbox',
    isFrontendFilter: true,
    options: []
  };
  const stopsMap = new Map<number, { numberOfStops: number }>();

  results.map((result) => {
    let numberOfStops = getNumberOfStops(result.outward);
    if (!stopsMap.has(numberOfStops)) {
      stopsMap.set(numberOfStops, { numberOfStops });
    }
  });

  stopsFilter.options = Array.from(stopsMap.values()).map((stop) => ({
    label: `${stop.numberOfStops == 0 ? 'direct' : stop.numberOfStops + ` Stop${stop.numberOfStops !== 1 ? 's' : ''}`}`,
    value: stop.numberOfStops,
    isChecked: false
  }));

  filters.push(stopsFilter);

  // Departure range
  const departureRangeFilter: Filter = {
    label: 'Departure Range',
    property: 'departureRange',
    type: 'checkbox',
    isFrontendFilter: true,
    options: []
  };
  const departureRangeMap = new Map<DepartureRange, DepartureRange>();
  results.map((result) => {
    const departureRange = rangeFromDateTimeInMinutes(getDepartureSegment(result.outward)?.departureDateTime);
    if (!departureRangeMap.has(departureRange)) {
      departureRangeMap.set(departureRange, departureRange);
    }
  });

  departureRangeFilter.options = orderBy(Array.from(departureRangeMap.values()), ['id'], ['asc']).map((range) => ({
    label: getDepartureRangeName(translations, range),
    value: range,
    isChecked: false
  }));

  filters.push(departureRangeFilter);

  // Departure Airport
  const departureAirportFilter: Filter = {
    label: 'Departure Airport',
    property: 'departureAirport',
    type: 'checkbox',
    isFrontendFilter: true,
    options: []
  };
  const departureAirportsMap = new Map<string, { name?: string; code: string }>();

  results.map((result) => {
    const departureSegment = getDepartureSegment(result.outward);
    const departureAirport = departureSegment?.departureAirportCode;
    if (departureAirport && !departureAirportsMap.has(departureAirport)) {
      departureAirportsMap.set(departureAirport, {
        name: departureSegment?.departureAirportName + ' (' + departureAirport + ')',
        code: departureAirport
      });
    }
  });

  departureAirportFilter.options = Array.from(departureAirportsMap.values()).map((airport) => ({
    label: airport.name ?? airport.code,
    value: airport.code,
    isChecked: false
  }));

  filters.push(departureAirportFilter);

  // Arrival Airport
  const arrivalAirportFilter: Filter = {
    label: 'Arrival Airport',
    property: 'arrivalAirport',
    type: 'checkbox',
    isFrontendFilter: true,
    options: []
  };
  const arrivalAirportsMap = new Map<string, { name?: string; code: string }>();

  results.map((result) => {
    const arrivalSegment = getArrivalSegment(result.outward);
    const arrivalAirport = arrivalSegment?.arrivalAirportCode;
    if (arrivalAirport && !arrivalAirportsMap.has(arrivalAirport)) {
      arrivalAirportsMap.set(arrivalAirport, {
        name: arrivalSegment?.arrivalAirportName + ' (' + arrivalAirport + ')',
        code: arrivalAirport
      });
    }
  });

  arrivalAirportFilter.options = Array.from(arrivalAirportsMap.values()).map((airport) => ({
    label: airport.name ?? airport.code,
    value: airport.code,
    isChecked: false
  }));

  filters.push(arrivalAirportFilter);

  // Price
  const priceFilter: Filter = {
    label: 'Price',
    property: 'price',
    type: 'slider',
    isFrontendFilter: true
  };

  const prices = results.map((r) => r.price ?? 0).filter((p) => p > 0);
  if (prices.length > 0) {
    priceFilter.min = Math.floor(Math.min(...prices));
    priceFilter.max = Math.ceil(Math.max(...prices));
  }

  filters.push(priceFilter);

  // Travel duration
  const travelDurationFilter: Filter = {
    label: 'Travel Duration',
    property: 'travelDuration',
    type: 'slider',
    isFrontendFilter: true
  };

  const minTravelTimeDuration = Math.min(...results.map((result) => result.outward.durationInTicks));
  const maxTravelTimeDuration = Math.max(...results.map((result) => result.outward.durationInTicks));
  const minTravelTimeValue = durationInTicksInMinutes(minTravelTimeDuration);
  const maxTravelTimeValue = durationInTicksInMinutes(maxTravelTimeDuration);
  if (minTravelTimeValue != null && maxTravelTimeValue != null) {
    travelDurationFilter.min = minTravelTimeValue;
    travelDurationFilter.max = maxTravelTimeValue;
  }

  filters.push(travelDurationFilter);

  return filters;
};

export const applyFilters = (results: BookingPackageItem[], filters: Filter[], sortBy: SortByType | null) => {
  const filtered = results.filter((r) => {
    return filters.every((filter) => {
      if (!filter.isFrontendFilter) return true;

      // ACCOMMODATION
      if (filter.property === 'accommodation') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;
        return selected.includes(r.accommodationCode);
      }

      // REGIME
      if (filter.property === 'regime') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;
        if (!r.regimeCode) return false;
        return selected.includes(r.regimeCode);
      }

      // PRICE
      if (filter.property === 'price') {
        if (filter.selectedMin != null && r.price < filter.selectedMin) return false;
        if (filter.selectedMax != null && r.price > filter.selectedMax) return false;
        return true;
      }

      // THEME
      if (filter.property === 'theme') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;

        return r.tagIds?.some((tagId) => selected.includes(tagId));
      }

      return true;
    });
  });

  // SORTING
  if (!sortBy || sortBy.label === 'default') {
    return filtered;
  }

  return filtered.sort((a, b) => {
    if (sortBy.label === 'price') {
      return sortBy.direction === 'asc' ? a.price - b.price : b.price - a.price;
    }

    return 0;
  });
};

export const applyFiltersToPackageAccoResults = (results: PackagingAccommodationResponse[], filters: Filter[], sortBy: SortByType | null) => {
  const filtered = results.filter((r) => {
    return filters.every((filter) => {
      if (!filter.isFrontendFilter) return true;

      // ACCOMMODATION
      if (filter.property === 'accommodation') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;
        const roomOptions = r.rooms.flatMap((room) => room.options);
        return roomOptions.some((option) => selected.includes(option.accommodationCode));
      }

      // REGIME
      if (filter.property === 'regime') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;
        const roomOptions = r.rooms.flatMap((room) => room.options);
        return roomOptions.some((option) => selected.includes(option.regimeCode));
      }

      // PRICE
      if (filter.property === 'price') {
        if (filter.selectedMin != null && r.price < filter.selectedMin) return false;
        if (filter.selectedMax != null && r.price > filter.selectedMax) return false;
        return true;
      }

      // RATING
      if (filter.property === 'rating') {
        if (r.stars == null) return false;
        if (filter.selectedRating != null && r.stars < filter.selectedRating) return false;

        return true;
      }

      return true;
    });
  });

  // SORTING
  if (!sortBy || sortBy.label === 'default') {
    return filtered;
  }

  return filtered.sort((a, b) => {
    if (sortBy.label === 'price') {
      return sortBy.direction === 'asc' ? a.price - b.price : b.price - a.price;
    }

    return 0;
  });
};

export const applyFiltersToPackageFlightResults = (results: PackagingFlightResponse[], filters: Filter[], sortBy: SortByType | null) => {
  const filtered = results.filter((result) => {
    return filters.every((filter) => {
      if (!filter.isFrontendFilter) return true;

      // Airline
      if (filter.property === 'airline') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;
        return selected.includes(result.airlineCode);
      }

      // Stops
      if (filter.property === 'numberOfStops') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;
        return selected.includes(getNumberOfStops(result.outward)) && selected.includes(getNumberOfStops(result.return));
      }

      // Departure range
      if (filter.property === 'departureRange') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;
        return selected.includes(rangeFromDateTimeInMinutes(getDepartureSegment(result.outward)?.departureDateTime));
      }

      // Departure airport
      if (filter.property === 'departureAirport') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;

        const departureAirportCode = getDepartureSegment(result.outward)?.departureAirportCode;
        if (!departureAirportCode) return false;

        return selected.includes(departureAirportCode);
      }

      // Arrival airport
      if (filter.property === 'arrivalAirport') {
        const selected = filter.options?.filter((o) => o.isChecked).map((o) => o.value);
        if (!selected || selected.length === 0) return true;

        const arrivalAirportCode = getArrivalSegment(result.outward)?.arrivalAirportCode;
        if (!arrivalAirportCode) return false;

        return selected.includes(arrivalAirportCode);
      }

      // PRICE
      if (filter.property === 'price') {
        if (filter.selectedMin != null && result.price < filter.selectedMin) return false;
        if (filter.selectedMax != null && result.price > filter.selectedMax) return false;
        return true;
      }

      // Travel times
      if (filter.property === 'travelDuration') {
        if (filter.selectedMin != null && durationInTicksInMinutes(result.outward?.durationInTicks) < filter.selectedMin) return false;
        if (filter.selectedMax != null && durationInTicksInMinutes(result.outward?.durationInTicks) > filter.selectedMax) return false;
        return true;
      }

      return true;
    });
  });

  // SORTING
  if (!sortBy || sortBy.label === 'default') {
    return filtered;
  }

  if (sortBy.label === 'departureTime') {
    return orderBy(
      results,
      [(result) => getDepartureSegment(result.outward)?.departureDateTime],
      [sortBy.direction] // or "desc"
    );
  } else if (sortBy.label === 'durationInTicks') {
    return orderBy(
      results,
      [(result) => durationInTicksInMinutes(result.outward?.durationInTicks ?? 0)],
      [sortBy.direction] // or "desc"
    );
  } else {
    return orderBy(results, [sortBy.label], [sortBy.direction]);
  }
};
