import JsonURL from "@jsonurl/jsonurl";
import { BookingPackageDetailsRequest, BookingPackagePax, BookingPackageRequest, BookingPackageRequestRoom } from "@qite/tide-client/build/types";
import { addDays, addMonths, format, formatISO } from "date-fns";
import { omit } from "lodash";
import React, { useContext, useEffect, useState } from "react";
import { ApiSettingsState } from "../../shared/types";
import { getTranslations } from "../../shared/utils/localization-util";
import { getDateAsDateFromParams, getRoomsFromParams } from "../../shared/utils/query-string-util";
import SettingsContext from "../settings-context";
import { DateRange, ProductRoom } from "../types";
import packageApi from "../utils/api";
import { formatPriceByMode } from "../utils/price";
import Dates from "./dates";
import Footer from "./footer";
import Header from "./header";
import Rooms from "./rooms";

interface ProductProps {
  productCode: string;
  productName: string;
  duration?: number;
  rating?: number;
}

const Product: React.FC<ProductProps> = ({
  productCode,
  productName,
  duration,
  rating
}) => {
  const {
    apiKey,
    apiUrl,
    officeId,
    agentId,
    catalogueId,
    includeFlights,
    language,
    basePath,
    priceMode,
    addProductToQuery,
    isOffer
  } = useContext(SettingsContext);
  const translations = getTranslations(language);

  const [loaded, setLoaded] = useState<boolean>(false);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [roomsIsDisabled, setRoomsIsDisabled] = useState<boolean>(true);
  const [price, setPrice] = useState<number>();
  const [hasFlight, setHasFlight] = useState<boolean>(false);
  const [hasTransfer, setHasTransfer] = useState<boolean>(false);
  const [rooms, setRooms] = useState<ProductRoom[]>([{ adults: 2, children: 0, childAges: [] }]);
  const [dateRange, setDateRange] = useState<DateRange>();
  const [packageProductName, setPackageProductName] = useState<string>(productName);

  const fetchPackage = async (signal: AbortSignal) => {
    if (
      loaded &&
      productCode &&
      dateRange?.fromDate &&
      dateRange?.toDate &&
      rooms
    ) {

      const apiSettingsState = (apiKey && apiUrl) ? {
        apiKey: apiKey,
        apiUrl: apiUrl
      } as ApiSettingsState : undefined;

      const startDate = formatISO(dateRange?.fromDate, { representation: "date" }) + "T00:00:00Z";
      const endDate = formatISO(dateRange?.toDate, { representation: "date" }) + "T00:00:00Z";

      const requestRooms = rooms.map((room, i) => {
        const requestRoom = {
          index: i,
          pax: []
        } as BookingPackageRequestRoom;

        for (var a = 0; a < room.adults; a++) {
          requestRoom.pax.push({
            age: 30,
          } as BookingPackagePax);
        }

        for (var c = 0; c < room.children; c++) {
          requestRoom.pax.push({
            age: room.childAges[c],
          } as BookingPackagePax);
        }

        return requestRoom;
      });

      const request = {
        officeId: officeId,
        agentId: agentId,
        payload: {
          searchType: 0,
          catalogueId: catalogueId,
          productCode: productCode,
          fromDate: startDate,
          toDate: endDate,
          includeFlights: includeFlights,
          rooms: requestRooms,
        } as BookingPackageDetailsRequest,
      } as BookingPackageRequest<BookingPackageDetailsRequest>;

      setIsLoading(true);
      const response = await packageApi.fetchDetails(request, signal, language, apiSettingsState);
      if (!response.errorCode && response.payload) {
        const selectedOption = response.payload.options.find(x => x.isSelected);
        if (selectedOption) {
          const hasFlight = selectedOption.includedServiceTypes.some(x => x === 7);
          const hasTranfer = selectedOption.includedServiceTypes.some(x => x === 13);

          setPrice(selectedOption.price);
          setHasFlight(hasFlight);
          setHasTransfer(hasTranfer);

          if (!productName) {
            setPackageProductName(selectedOption.name);
          }
        }
      } else {
        setPrice(undefined);
        setHasFlight(false);
        setHasTransfer(false);
      }

      setIsLoading(false);
    }
  }

  const handleBookClick = () => {
    const params: Record<string, string> = {};

    if (rooms) {
      const serialized = JsonURL.stringify(
        rooms.map((room) => omit(room, ["children"])),
        { AQF: true }
      );

      if (serialized) {
        params["rooms"] = serialized;
      }
    }

    if (dateRange?.fromDate) {
      params["startDate"] = format(dateRange.fromDate, "yyyy-MM-dd");
    }

    if (dateRange?.toDate) {
      params["endDate"] = format(dateRange.toDate, "yyyy-MM-dd");
    }

    params["catalog"] = catalogueId.toString();

    if (addProductToQuery) {
      params["productCode"] = productCode;
      params["productName"] = encodeURI(packageProductName)!;
    }

    const path = window.location.pathname;
    const paramString = Object.keys(params)
      .map((key) => `${key}=${params[key]}`)
      .join("&");

    window.location.href = basePath.startsWith('/')
      ? `${window.location.protocol}//${window.location.host}${basePath}?${paramString}`
      : `${path}${path.endsWith("/") ? "" : "/"}${basePath}?${paramString}`
  }

  const handleRoomChange = (rooms: ProductRoom[]) => {
    setRooms(rooms);
  }

  const handleDateChange = (value: DateRange) => {
    setDateRange(value);
  }

  useEffect(() => {
    const controller = new AbortController();
    const { signal } = controller;

    (async () => {
      fetchPackage(signal);
    })();
    return () => {
      controller.abort();
    };
  }, [
    dateRange?.fromDate?.valueOf(),
    dateRange?.toDate?.valueOf(),
    JSON.stringify(rooms)
  ]);

  useEffect(() => {
    const params = new URLSearchParams(location.search);
    const rooms = getRoomsFromParams(params, "rooms");
    const from = getDateAsDateFromParams(params, "from");
    const to = getDateAsDateFromParams(params, "to");

    if (rooms) {
      setRooms(rooms);
    }

    if (from && duration) {
      const durationTo = new Date(
        Date.UTC(from.getFullYear(), from.getMonth(), from.getDate() + duration)
      );

      setDateRange({ fromDate: from, toDate: durationTo });
    } else if (from && to) {
      setDateRange({ fromDate: from, toDate: to });
    } else if (duration) {
      const now = new Date();

      const durationFrom = new Date(Date.UTC(now.getFullYear(), now.getMonth() + 3, now.getDate()));
      const durationTo = new Date(
        Date.UTC(
          durationFrom.getFullYear(),
          durationFrom.getMonth(),
          durationFrom.getDate() + duration
        )
      );

      setDateRange({ fromDate: durationFrom, toDate: durationTo });
    } else {
      const now = new Date();
      const startDate = addMonths(now, 1);
      const endDate = addDays(startDate, 7);

      setDateRange({ fromDate: startDate, toDate: endDate });
    }

    setLoaded(true);
  }, [location]);

  const personCount = rooms.reduce((s, r) => s + r.adults + r.children, 0);
  const durationCount = 0;
  const priceText = formatPriceByMode(
    price,
    priceMode,
    personCount,
    durationCount,
    translations.PRODUCT.PER_PERSON,
    translations.PRODUCT.PER_NIGHT,
    translations.PRODUCT.PER_PERSON_PER_NIGHT
  );

  return (
    <div className="booking-product">
      <Header
        name={packageProductName}
        rating={rating}
        priceText={priceText}
        isLoading={isLoading}
        hasFlight={hasFlight}
        hasTransfer={hasTransfer} />
      <div className="booking-product__body">
        <Rooms
          rooms={rooms}
          isDisabled={roomsIsDisabled}
          setIsDisabled={setRoomsIsDisabled}
          onChange={handleRoomChange} />
        <Dates
          value={dateRange}
          duration={duration}
          onChange={handleDateChange} />
      </div>
      <Footer
        priceText={priceText}
        isLoading={isLoading}
        isOffer={isOffer}
        roomsIsDisabled={roomsIsDisabled}
        handleBookClick={handleBookClick} />
    </div>
  );
}

export default Product;