import React, { useContext, useMemo } from 'react';
import { differenceInCalendarDays, format } from 'date-fns';
import { first, groupBy, isEmpty, last } from 'lodash';
import { PackagingEntryLine, PackagingEntryLineFlightLine } from '@qite/tide-client';
import Icon from '../../../shared/components/icon';
import SearchResultsConfigurationContext from '../../search-results-configuration-context';
import { formatPrice, getDateOnlyTime, getTranslations } from '../../../shared/utils/localization-util';
import { useDispatch, useSelector } from 'react-redux';
import { SearchResultsRootState } from '../../store/search-results-store';
import { ACCOMMODATION_SERVICE_TYPE, FLIGHT_SERVICE_TYPE } from '../../utils/query-utils';
import Spinner from '../spinner/spinner';
import { setBookPackagingEntry } from '../../store/search-results-slice';

interface ItineraryProps {
  isOpen: boolean;
  handleSetIsOpen: () => void;
  isLoading?: boolean;
  onEditAccommodation?: (segments: PackagingEntryLine[]) => void;
}

const getFlightLines = (flight?: PackagingEntryLine): PackagingEntryLineFlightLine[] => {
  return flight?.flightInformation?.flightLines ?? [];
};

const getDepartureTime = (flight?: PackagingEntryLine): string => {
  const firstLine = first(getFlightLines(flight));
  if (!firstLine?.departureTime) return '';

  return firstLine.departureTime.slice(0, 5);
};

const getArrivalTime = (flight?: PackagingEntryLine): string => {
  const lastLine = last(getFlightLines(flight));
  if (!lastLine?.arrivalTime) return '';

  return lastLine.arrivalTime.slice(0, 5);
};

const getDuration = (flight?: PackagingEntryLine): string => {
  const lines = getFlightLines(flight);
  if (!lines.length) return '';

  const totalTicks = lines.reduce((sum, line) => sum + (line.durationInTicks ?? 0), 0) || 0;

  if (!totalTicks) return '';

  const seconds = totalTicks / 10_000_000;
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);

  return `${hours}h ${minutes.toString().padStart(2, '0')}m`;
};

const numberOfNights = (segment: PackagingEntryLine) => {
  return differenceInCalendarDays(new Date(segment.to), new Date(segment.from));
};

const getSegmentIcon = (segment: PackagingEntryLine) => {
  switch (segment.serviceType) {
    case 3:
      return (
        <div className="search__filter__itinerary__segment-badge search__filter__itinerary__segment-badge--secondary">
          <Icon name="ui-bed" width={15} height={15} />
        </div>
      );
    case 4:
      return (
        <div className="search__filter__itinerary__segment-badge search__filter__itinerary__segment-badge--secondary">
          <Icon name="ui-ticket" width={15} height={15} />
        </div>
      );
    case 11:
      return (
        <div className="search__filter__itinerary__segment-badge search__filter__itinerary__segment-badge--secondary">
          <Icon name="ui-ship" width={15} height={15} />
        </div>
      );
    case 13:
    case 17:
    case 22:
      return (
        <div className="search__filter__itinerary__transport-badge">
          <Icon name="ui-car" width={15} height={15} />
        </div>
      );
    default:
      return (
        <div className="search__filter__itinerary__segment-badge">
          <Icon name="ui-location" width={15} height={15} />
        </div>
      );
  }
};

const canEdit = (segment: PackagingEntryLine) => {
  if (segment.serviceType === ACCOMMODATION_SERVICE_TYPE) {
    return true;
  }
  return false;
};

const getSegmentTitle = (segment: PackagingEntryLine) => {
  return segment.productName ?? segment.accommodationName;
};

const SERVICE_TYPE_PRIORITY: Record<number, number> = {
  7: 0, // Flight
  13: 1, // Transfer
  3: 2, // Hotel
  4: 3 // Excursion
};

const getServiceTypePriority = (serviceType?: number) => {
  return SERVICE_TYPE_PRIORITY[serviceType ?? -1] ?? 2;
};

const Itinerary: React.FC<ItineraryProps> = ({ isOpen, handleSetIsOpen, isLoading, onEditAccommodation }) => {
  const context = useContext(SearchResultsConfigurationContext);
  const translations = getTranslations(context?.languageCode ?? 'en-GB');
  const { editablePackagingEntry, priceDetails } = useSelector((state: SearchResultsRootState) => state.searchResults);

  const dispatch = useDispatch();

  const packagingEntry = editablePackagingEntry ?? context?.packagingEntry;

  const sortedLines = useMemo(() => {
    return [...(packagingEntry?.lines ?? [])].sort((a, b) => {
      const dateA = getDateOnlyTime(a.from);
      const dateB = getDateOnlyTime(b.from);

      if (dateA !== dateB) {
        return dateA - dateB;
      }

      const priorityA = getServiceTypePriority(a.serviceType);
      const priorityB = getServiceTypePriority(b.serviceType);

      if (priorityA !== priorityB) {
        return priorityA - priorityB;
      }

      return (a.order ?? Infinity) - (b.order ?? Infinity);
    });
  }, [packagingEntry]);

  if (!packagingEntry) {
    return null;
  }

  const firstEntryLine = first(sortedLines);
  const lastEntryLine = last(sortedLines);

  const accommodationLine = sortedLines.find((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE) ?? firstEntryLine;

  const country = accommodationLine?.country?.name ?? firstEntryLine?.country?.name;
  const location = accommodationLine?.location?.name ?? accommodationLine?.oord?.name ?? accommodationLine?.region?.name ?? firstEntryLine?.location?.name;

  const flightSegments = sortedLines.filter((item) => item.serviceType === FLIGHT_SERVICE_TYPE);
  const outboundFlight = first(flightSegments);
  const returnFlight = flightSegments.length > 1 ? last(flightSegments) : undefined;

  const otherSegments = sortedLines.filter((item) => item.serviceType !== FLIGHT_SERVICE_TYPE);
  const grouped = groupBy(otherSegments, (segment) => {
    return `${segment.productCode}-${segment.from}-${segment.to}`;
  });
  const groupedOtherSegments = Object.entries(grouped).map(([key, segments]) => ({
    key,
    segments
  }));

  const numberOfPax = packagingEntry.pax?.length || 1;
  const totalPrice = priceDetails?.total || packagingEntry.price || 0;
  const pricePerPerson = totalPrice / numberOfPax;

  const handleConfirm = () => {
    dispatch(setBookPackagingEntry(true));
  };

  return (
    <div className={`search__filters--modal ${isOpen ? 'is-open' : ''}`}>
      <div className="search__filters--background" onClick={handleSetIsOpen}></div>

      <button className="search__filters--close" onClick={handleSetIsOpen}>
        <Icon name="ui-close" height={24} />
      </button>

      <div className="search__filters">
        <div className="search__filter-row search__filter__header">
          <div className="search__filter-row-flex-title">
            <p className="search__filter-small-title">{translations.SRP.ITINERARY_TITLE}</p>
          </div>
        </div>

        <>
          <div className="search__filter-group">
            {context?.destinationImage && (
              <div className="search__filter__image__wrapper">
                <img src={context.destinationImage.url} alt={context.destinationImage.alt} className="search__filter__image" />

                {packagingEntry?.dossierNumber && (
                  <span className="search__filter__image__text">
                    {translations.SRP.DOSSIER_NUMBER}: {packagingEntry.dossierNumber}
                  </span>
                )}

                <h4 className="search__filter__image__title">{(location || '') + (location && country ? ' - ' : '') + (country || '')}</h4>
              </div>
            )}
          </div>

          <div className="search__filter__prices">
            {isLoading ? (
              <Spinner label={translations.PRODUCT.LOADING_PRICE} />
            ) : (
              <>
                <div className="search__filter__prices__wrapper">
                  <h3 className="search__filter__prices--amount">{formatPrice(pricePerPerson, 'EUR')}</h3>
                  <p>{translations.SRP.PACKAGE_PRICE_PER_PERSON}</p>
                  <p>
                    <strong>
                      ({formatPrice(totalPrice, 'EUR')} {translations.SRP.TOTAL})
                    </strong>
                  </p>
                </div>
                <button className="cta" onClick={handleConfirm}>
                  {translations.QSM.CONFIRM}
                </button>
              </>
            )}
          </div>

          <div className="search__filter__itinerary">
            <p>{translations.SRP.DAY_BY_DAY}</p>

            {firstEntryLine && (
              <div className="search__filter__itinerary__country">
                <div className="search__filter__itinerary__country-icon">
                  <Icon name="ui-flag" width={17.5} height={20} />
                </div>
                <div className="search__filter__itinerary__country-content">
                  <p>
                    {format(new Date(firstEntryLine.from), 'EEE. d MMM yyyy')} - <strong>{translations.SRP.START}</strong>
                  </p>
                </div>
              </div>
            )}

            {outboundFlight && (
              <div className="search__filter__itinerary__transport">
                <div className="search__filter__itinerary__transport-timeline">
                  <div className="search__filter__itinerary__transport-timeline-line"></div>
                </div>

                <div className="search__filter__itinerary__transport-item">
                  <div className="search__filter__itinerary__transport-date">
                    <p className="search__filter__itinerary__transport-date-date">
                      <strong>{format(new Date(outboundFlight.from), 'd')}</strong>
                    </p>
                    <p>{format(new Date(outboundFlight.from), 'MMM')}</p>
                  </div>

                  <div className="search__filter__itinerary__transport-badge">
                    <Icon name="ui-plane" height={15} />
                  </div>

                  <div className="search__filter__itinerary__transport-details">
                    <h6>{outboundFlight.productName}</h6>
                    <p className="search__filter__itinerary__transport-details-plane">
                      <span>
                        <Icon name="ui-plane-depart" height={14} /> <strong>{getDepartureTime(outboundFlight)}</strong>
                      </span>{' '}
                      -{' '}
                      <span>
                        <Icon name="ui-plane-arrive" height={14} /> <strong>{getArrivalTime(outboundFlight)}</strong>
                      </span>
                    </p>
                    <p className="search__filter__itinerary__transport-details-time">
                      <span>
                        <Icon name="ui-clock" height={20} /> {getDuration(outboundFlight)}
                      </span>
                    </p>
                  </div>
                </div>
              </div>
            )}

            {!isEmpty(groupedOtherSegments) &&
              groupedOtherSegments.map((group) => {
                const firstSegment = first(group.segments);
                if (!firstSegment) return null;

                return (
                  <div className="search__filter__itinerary__segments">
                    <div className="search__filter__itinerary__segments__wrapper" key={group.key}>
                      <div className="search__filter__itinerary__segments-timeline">
                        <div className="search__filter__itinerary__segments-timeline-line"></div>
                      </div>

                      <div className="search__filter__itinerary__segment">
                        <div className="search__filter__itinerary__segment-item search__filter__itinerary__segment-item--start">
                          <div className="search__filter__itinerary__transport-date">
                            <p className="search__filter__itinerary__transport-date-date">
                              <strong>{format(new Date(firstSegment.from), 'd')}</strong>
                            </p>
                            <p>{format(new Date(firstSegment.from), 'MMM')}</p>
                          </div>

                          <div className="search__filter__itinerary__segment-badge">
                            <Icon name="ui-location" width={15} height={15} />
                          </div>

                          <div className="search__filter__itinerary__segment-details">
                            <h6>
                              {firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name}
                              {(firstSegment.location?.name || firstSegment.oord?.name || firstSegment.region?.name) && firstSegment.country?.name ? ', ' : ''}
                              {firstSegment.country?.name}
                            </h6>
                            <p className="search__filter__itinerary__segment-details-text">
                              {format(new Date(firstSegment.from), 'EEE. d MMM yyyy')}
                              &gt; {format(new Date(firstSegment.to), 'EEE. d MMM yyyy')}
                            </p>
                          </div>
                        </div>
                      </div>

                      <div className="search__filter__itinerary__segment">
                        <div
                          className={`search__filter__itinerary__segment-item ${
                            canEdit(firstSegment) ? 'search__filter__itinerary__segment-item--editable' : ''
                          }`}
                          onClick={() => {
                            if (canEdit(firstSegment) && onEditAccommodation) {
                              onEditAccommodation(group.segments);
                            }
                          }}>
                          <div className="search__filter__itinerary__segment-date search__filter__itinerary__segment-nights">
                            {firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE && (
                              <>
                                <p className="search__filter__itinerary__segment-date-date">
                                  <strong>{numberOfNights(firstSegment)}</strong>
                                </p>
                                <Icon name="ui-moon" width={16} height={16} />
                              </>
                            )}
                          </div>

                          {getSegmentIcon(firstSegment)}

                          <div className="search__filter__itinerary__segment-details">
                            <h6>{getSegmentTitle(firstSegment)}</h6>
                            {firstSegment.serviceType === ACCOMMODATION_SERVICE_TYPE &&
                              group.segments.map((segment, index) => (
                                <React.Fragment key={segment.guid}>
                                  <strong>
                                    {translations.SHARED.ROOM}&nbsp;{index + 1}
                                  </strong>
                                  {segment.productName && segment.accommodationName && (
                                    <div className="search__filter__itinerary__segment-details__room">
                                      <Icon name="ui-bed" width={12} height={12} />
                                      {segment.accommodationName}
                                    </div>
                                  )}
                                  {segment.regimeName && (
                                    <div className="search__filter__itinerary__segment-details__room">
                                      <Icon name="ui-utensils" width={12} height={12} />
                                      {segment.regimeName}
                                    </div>
                                  )}
                                </React.Fragment>
                              ))}
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })}

            {returnFlight && returnFlight !== outboundFlight && (
              <div className="search__filter__itinerary__transport">
                <div className="search__filter__itinerary__transport-timeline">
                  <div className="search__filter__itinerary__transport-timeline-line"></div>
                </div>

                <div className="search__filter__itinerary__transport-item">
                  <div className="search__filter__itinerary__transport-date">
                    <p className="search__filter__itinerary__transport-date-date">
                      <strong>{format(new Date(returnFlight.from), 'd')}</strong>
                    </p>
                    <p>{format(new Date(returnFlight.from), 'MMM')}</p>
                  </div>

                  <div className="search__filter__itinerary__transport-badge">
                    <Icon name="ui-plane" height={15} />
                  </div>

                  <div className="search__filter__itinerary__transport-details">
                    <h6>{returnFlight.productName}</h6>
                    <p className="search__filter__itinerary__transport-details-plane">
                      <span>
                        <Icon name="ui-plane-depart" height={14} /> <strong>{getDepartureTime(returnFlight)}</strong>
                      </span>{' '}
                      -{' '}
                      <span>
                        <Icon name="ui-plane-arrive" height={14} /> <strong>{getArrivalTime(returnFlight)}</strong>
                      </span>
                    </p>
                    <p className="search__filter__itinerary__transport-details-time">
                      <span>
                        <Icon name="ui-clock" height={20} /> {getDuration(returnFlight)}
                      </span>
                    </p>
                  </div>
                </div>
              </div>
            )}

            {lastEntryLine && (
              <div className="search__filter__itinerary__country">
                <div className="search__filter__itinerary__country-icon">
                  <Icon name="ui-flag" width={17.5} height={20} />
                </div>
                <div className="search__filter__itinerary__country-content">
                  <p>
                    {format(new Date(lastEntryLine.to), 'EEE. d MMM yyyy')} - <strong>{translations.SRP.END}</strong>
                  </p>
                </div>
              </div>
            )}
          </div>
        </>
      </div>
    </div>
  );
};

export default Itinerary;
