import {
  PackagingEntryLine,
  PackagingEntryPax,
  BookingPackagePax,
  PackagingEntry,
  BookingPackageRequestRoom,
  PackagingRoom,
  PackagingTraveller
} from '@qite/tide-client';
import { range } from 'lodash';

export const GROUP_TOUR_SERVICE_TYPE = 1;
export const ACCOMMODATION_SERVICE_TYPE = 3;
export const EXCURSION_SERVICE_TYPE = 4;
export const FLIGHT_SERVICE_TYPE = 7;

export const toDateOnlyString = (value: string | Date): string => {
  const date = value instanceof Date ? value : new Date(value);
  return date.toISOString().split('T')[0];
};

const getAgeAtReferenceDate = (dateOfBirth: string | Date, referenceDate: string | Date): number => {
  const dob = dateOfBirth instanceof Date ? dateOfBirth : new Date(dateOfBirth);
  const ref = referenceDate instanceof Date ? referenceDate : new Date(referenceDate);

  let age = ref.getFullYear() - dob.getFullYear();
  const monthDiff = ref.getMonth() - dob.getMonth();

  if (monthDiff < 0 || (monthDiff === 0 && ref.getDate() < dob.getDate())) {
    age--;
  }

  return age;
};

export const getPrimaryAccommodationLine = (lines: PackagingEntryLine[]): PackagingEntryLine | undefined => {
  return [...lines]
    .filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE)
    .sort((a, b) => new Date(a.from).getTime() - new Date(b.from).getTime())[0];
};

const getFlightLines = (lines: PackagingEntryLine[]): PackagingEntryLine[] => {
  return [...lines].filter((line) => line.serviceType === FLIGHT_SERVICE_TYPE).sort((a, b) => new Date(a.from).getTime() - new Date(b.from).getTime());
};

export const getDepartureAirportFromEntry = (lines: PackagingEntryLine[]): string | null => {
  const firstFlight = getFlightLines(lines)[0];
  const firstSegment = firstFlight?.flightInformation?.flightLines?.[0];
  return firstSegment?.departureAirportCode ?? null;
};

export const getDestinationAirportFromEntry = (lines: PackagingEntryLine[]): string | null => {
  const outboundFlight = getFlightLines(lines)[0];
  const flightSegments = outboundFlight?.flightInformation?.flightLines;

  if (!flightSegments?.length) return null;

  return flightSegments[flightSegments.length - 1]?.arrivalAirportCode ?? null;
};

const mapPackagingPaxToBookingPax = (pax: PackagingEntryPax | undefined, fallbackId: number, referenceDate: string): BookingPackagePax => ({
  id: pax?.id ?? fallbackId,
  guid: pax?.id?.toString() ?? fallbackId.toString(),
  firstName: pax?.firstName ?? '',
  lastName: pax?.lastName ?? '',
  dateOfBirth: pax?.dateOfBirth ?? undefined,
  age: pax?.dateOfBirth ? getAgeAtReferenceDate(pax.dateOfBirth, referenceDate) : undefined,
  isMainBooker: pax?.isMainBooker,
  email: ''
});

export const getRequestRoomsFromPackagingEntry = (entry: PackagingEntry): BookingPackageRequestRoom[] => {
  const accommodationLines = (entry.lines ?? []).filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE && line.pax?.length > 0);

  const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));

  if (!accommodationLines.length) {
    return [
      {
        index: 0,
        pax: (entry.pax ?? []).map((p) => mapPackagingPaxToBookingPax(p, p.id, new Date().toISOString()))
      }
    ];
  }

  const roomGroups: BookingPackagePax[][] = [];

  accommodationLines.forEach((line) => {
    const groupedByRoom = new Map<number, BookingPackagePax[]>();

    line.pax.forEach((linePax) => {
      const roomIndexWithinLine = Number(linePax.room ?? 0);
      const paxId = Number(linePax.paxId);
      const pax = mapPackagingPaxToBookingPax(paxById.get(paxId), paxId, line.from);

      if (!groupedByRoom.has(roomIndexWithinLine)) {
        groupedByRoom.set(roomIndexWithinLine, []);
      }

      groupedByRoom.get(roomIndexWithinLine)!.push(pax);
    });

    const sortedGroups = Array.from(groupedByRoom.entries())
      .sort(([a], [b]) => a - b)
      .map(([, pax]) => pax);

    roomGroups.push(...sortedGroups);
  });

  if (!roomGroups.length) {
    return [
      {
        index: 0,
        pax: (entry.pax ?? []).map((p) => mapPackagingPaxToBookingPax(p, p.id, accommodationLines[0].from))
      }
    ];
  }

  return roomGroups.map((pax, index) => ({
    index,
    pax
  }));
};

export const parseHotelId = (line?: PackagingEntryLine): number | null => {
  if (!line?.productCode) return null;
  const parsed = Number(line.productCode);
  return Number.isNaN(parsed) ? null : parsed;
};

export const getPackagingRequestRoomsFromBookingRooms = (rooms: BookingPackageRequestRoom[] | null) => {
  if (!rooms?.length) {
    const room = { index: 0, travellers: [] } as PackagingRoom;
    range(0, 2).forEach(() => {
      room.travellers.push({
        age: 30
      } as PackagingTraveller);
    });
    return [room];
  }

  return rooms.map((x, i) => {
    const room = { index: x.index ?? i, travellers: [] } as PackagingRoom;

    x.pax.forEach((p) => {
      room.travellers.push({
        age: p.age ?? 30
      } as PackagingTraveller);
    });

    return room;
  });
};
