import React, { useContext, useState } from 'react';
import { FlyInType, HotelResult, SearchResultsConfiguration } from '../../types';
import Spinner from '../spinner/spinner';
import HotelCard from './hotel-card';
import { useDispatch, useSelector } from 'react-redux';
import { SearchResultsRootState } from '../../store/search-results-store';
import { BookingPackageItem, PackagingAccommodationResponse, PortalQsmType } from '@qite/tide-client';
import { format, parseISO } from 'date-fns';
import { calculateNights, formatPrice, getTranslations } from '../../../shared/utils/localization-util';
import SearchResultsConfigurationContext from '../../search-results-configuration-context';
import { first } from 'lodash';
import Icon from '../../../shared/components/icon';
import { setFlyInIsOpen, setFlyInType } from '../../store/search-results-slice';

interface HotelAccommodationResultsProps {
  isLoading: boolean;
  isFlyIn?: boolean;
}

const getLocation = (locationName?: string, regionName?: string, countryName?: string, fallback?: string): string => {
  if (locationName || regionName) {
    return `${locationName || regionName}${countryName ? `, ${countryName}` : ''}`;
  }

  return fallback || '';
};

const getBaseHotelResult = (
  searchResult: {
    code: string;
    name: string;
    locationName?: string;
    regionName?: string;
    countryName?: string;
    price: number;
    currencyCode: string;
  },
  cmsItem: any,
  languageCode?: string,
  translations?: any
) => ({
  type: 'hotel' as const,
  code: searchResult.code,
  title: cmsItem?.content?.general?.title || searchResult.name,
  image: cmsItem?.content?.images?.thumbnailPicture?.url,
  description: cmsItem?.content?.descriptions?.introductionTitle || '',
  location: getLocation(searchResult.locationName, searchResult.regionName, searchResult.countryName, cmsItem?.parentItem?.name),
  price: formatPrice(searchResult.price, searchResult.currencyCode, languageCode),
  ctaText: translations?.SRP.VIEW_DETAILS
});

const mapBookingPackageResult = (searchResult: BookingPackageItem, cmsItem: any, languageCode?: string, translations?: any): HotelResult => {
  return {
    ...getBaseHotelResult(searchResult, cmsItem, languageCode, translations),
    id: searchResult.productId,
    days: `${calculateNights(searchResult.stayFromDate, searchResult.stayToDate)} ${translations?.SRP.NIGHTS}`,
    accommodation: searchResult.accommodationName,
    regime: searchResult.regimeName,
    stars: cmsItem?.content?.general?.stars || searchResult.hotelStars
  };
};

const mapPackagingAccoResult = (searchResult: PackagingAccommodationResponse, cmsItem: any, languageCode?: string, translations?: any): HotelResult => {
  const selectedOption = first(searchResult.rooms)?.options?.find((x) => x.isSelected);

  return {
    ...getBaseHotelResult(searchResult, cmsItem, languageCode, translations),
    days: `${calculateNights(new Date(searchResult.fromDate), new Date(searchResult.toDate))} ${translations?.SRP.NIGHTS}`,
    accommodation: selectedOption?.accommodationName || '',
    regime: selectedOption?.regimeName || '',
    stars: cmsItem?.content?.general?.stars,
    contents: searchResult.contents
  };
};

const renderHotelResults = (
  results: HotelResult[],
  context: SearchResultsConfiguration,
  activeTab: string | null,
  translations: any,
  selectedPackagingAccoResult?: HotelResult,
  isFlyIn?: boolean
) => {
  const renderedResults = results.map((result, index) => {
    const key = `${result.id ?? result.code}-${index}`;

    if (context?.showCustomCards && context?.customCardRenderer) {
      return (
        <div key={key} className="search__result-card">
          {context.customCardRenderer(result)}
        </div>
      );
    }

    return <HotelCard key={key} result={result} translations={translations} />;
  });

  return (
    <div className={`search__results__cards ${activeTab ? `search__results__cards--${activeTab}` : ''}`}>
      {selectedPackagingAccoResult && !isFlyIn && (
        <HotelCard key={selectedPackagingAccoResult.code} result={selectedPackagingAccoResult} translations={translations} />
      )}
      {renderedResults}
    </div>
  );
};

const HotelAccommodationResults: React.FC<HotelAccommodationResultsProps> = ({ isLoading, isFlyIn }) => {
  const context = useContext(SearchResultsConfigurationContext);
  const dispatch = useDispatch();
  if (!context) {
    return null;
  }

  const translations = getTranslations(context.languageCode ?? 'en-GB');

  const { filteredResults, filteredPackagingAccoResults, packagingAccoResults, activeTab, flyInIsOpen, selectedPackagingAccoResultCode } = useSelector(
    (state: SearchResultsRootState) => state.searchResults
  );

  const cmsMap = React.useMemo(() => {
    const map = new Map();

    context.cmsHotelData?.forEach((item) => {
      const code = item?.content?.general?.product?.code;
      if (code) {
        map.set(code, item);
      }
    });

    return map;
  }, [context.cmsHotelData]);

  const mappedResults = React.useMemo(() => {
    if (context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && !context.searchConfiguration.enableManualPackaging) {
      return filteredResults.map((result) => mapBookingPackageResult(result, cmsMap.get(result.code), context.languageCode, translations));
    }

    if (
      context.searchConfiguration.qsmType === PortalQsmType.Accommodation ||
      (context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && context.searchConfiguration.enableManualPackaging)
    ) {
      return filteredPackagingAccoResults.map((result) => mapPackagingAccoResult(result, cmsMap.get(result.code), context.languageCode, translations));
    }

    return [];
  }, [
    context.searchConfiguration.qsmType,
    context.searchConfiguration.enableManualPackaging,
    context.languageCode,
    filteredResults,
    filteredPackagingAccoResults,
    cmsMap,
    translations
  ]);

  const firstBookingResult = filteredResults?.[0];
  const firstPackagingResult = filteredPackagingAccoResults?.[0];

  const firstResultDate =
    context.searchConfiguration.qsmType === PortalQsmType.AccommodationAndFlight && !context.searchConfiguration.enableManualPackaging
      ? firstBookingResult?.fromDate
      : firstPackagingResult?.fromDate;

  const firstResultDay = firstResultDate ? format(parseISO(firstResultDate), 'd') : null;
  const firstResultMonth = firstResultDate ? format(parseISO(firstResultDate), 'MMM') : null;

  const selectedPackagingAccoResult = React.useMemo(() => {
    const selectedResult = packagingAccoResults.find((result) => result.code === selectedPackagingAccoResultCode);
    if (selectedResult) {
      return mapPackagingAccoResult(selectedResult, cmsMap.get(selectedResult.code), context.languageCode, translations);
    }
  }, [packagingAccoResults, selectedPackagingAccoResultCode, cmsMap, context.languageCode, translations]);

  const visibleResults = React.useMemo(() => {
    const shouldShowAll = context?.searchConfiguration.qsmType !== PortalQsmType.AccommodationAndFlight || isFlyIn;

    let filteredMapperResults = mappedResults;

    if (selectedPackagingAccoResult) {
      filteredMapperResults = mappedResults.filter((result) => result.code !== selectedPackagingAccoResult.code);
    }

    if (shouldShowAll) {
      if (isFlyIn) {
        return mappedResults;
      }
      return filteredMapperResults;
    }

    if (selectedPackagingAccoResult) {
      return filteredMapperResults.filter((result) => result.code !== selectedPackagingAccoResult.code).slice(0, 2);
    }

    return mappedResults.slice(0, 3);
  }, [context?.searchConfiguration.qsmType, mappedResults, isFlyIn, selectedPackagingAccoResult]);

  const handleShowMoreHotels = (flyInType: FlyInType) => {
    dispatch(setFlyInType(flyInType));
    dispatch(setFlyInIsOpen(true));
  };

  return (
    <>
      {!isFlyIn && (
        <div className="search__results__label search__results__label--secondary">
          <div className="search__results__label__date">
            {/* /* {firstResultDay && firstResultMonth ? (
              <>
                <p className="search__results__label__date-date">{firstResultDay}</p>
                <p>{firstResultMonth}</p>
              </>
            ) : (
              <Icon name="ui-bed" height={16} fill="white" />
            )} */}
            <p className="search__results__label__date-date">{firstResultDay}</p>
            <p>{firstResultMonth}</p>
          </div>
          <div className="search__results__label__text">
            <Icon name="ui-bed" height={16} />
            <h3>
              {translations.SRP.SELECT} <strong>{translations.SRP.ACCOMMODATION}</strong>
            </h3>
          </div>
        </div>
      )}
      {isLoading ? (
        <>{context.customSpinner ?? <Spinner label={translations.SRP.LOADING_ACCOMMODATIONS} />}</>
      ) : (
        renderHotelResults(visibleResults, context, activeTab, translations, selectedPackagingAccoResult, isFlyIn)
      )}
      {packagingAccoResults.length > 3 && !isFlyIn && (
        <div className="search__results__cards__actions">
          <button className="cta cta--secondary" onClick={() => handleShowMoreHotels('acco-results')}>
            {translations.SRP.SHOW_MORE}
          </button>
        </div>
      )}
      {mappedResults.length === 0 && !isLoading && <div className="no-results">{translations.SRP.NO_RESULTS}</div>}
    </>
  );
};

export default HotelAccommodationResults;
