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;
