import {
  CalendarIcon,
  ClockIcon,
  CreditCardIcon,
  ExclamationIcon,
  LocationMarkerIcon,
} from "@heroicons/react/solid";
import { EventTypeCustomInputType } from "@prisma/client";
import dayjs from "dayjs";
import Head from "next/head";
import { useRouter } from "next/router";
import { stringify } from "querystring";
import { useCallback, useEffect, useState } from "react";
import { FormattedNumber, IntlProvider } from "react-intl";
import { ReactMultiEmail } from "react-multi-email";
import PhoneInput from "react-phone-number-input";
import "react-phone-number-input/style.css";

import { createPaymentLink } from "@ee/lib/stripe/client";

import { asStringOrNull } from "@lib/asStringOrNull";
import { timeZone } from "@lib/clock";
import useTheme from "@lib/hooks/useTheme";
import { LocationType } from "@lib/location";
import createBooking from "@lib/mutations/bookings/create-booking";
import { parseZone } from "@lib/parseZone";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
import { BookingCreateBody } from "@lib/types/booking";

import AvatarGroup from "@components/ui/AvatarGroup";
import { Button } from "@components/ui/Button";

import { BookPageProps } from "../../../pages/[user]/book";
import { TeamBookingPageProps } from "../../../pages/team/[slug]/book";

type BookingPageProps = BookPageProps | TeamBookingPageProps;

const BookingPage = (props: BookingPageProps) => {
  const router = useRouter();
  const { rescheduleUid } = router.query;
  const { isReady } = useTheme(props.profile.theme);

  const date = asStringOrNull(router.query.date);
  const timeFormat = asStringOrNull(router.query.clock) === "24h" ? "H:mm" : "h:mma";

  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [guestToggle, setGuestToggle] = useState(false);
  const [guestEmails, setGuestEmails] = useState([]);
  const locations = props.eventType.locations || [];

  const [selectedLocation, setSelectedLocation] = useState<LocationType>(
    locations.length === 1 ? locations[0].type : ""
  );

  const telemetry = useTelemetry();

  useEffect(() => {
    telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.timeSelected, collectPageParameters()));
  }, []);

  function toggleGuestEmailInput() {
    setGuestToggle(!guestToggle);
  }

  const locationInfo = (type: LocationType) => locations.find((location) => location.type === type);

  // TODO: Move to translations
  const locationLabels = {
    [LocationType.InPerson]: "Link or In-person meeting",
    [LocationType.Phone]: "Phone call",
    [LocationType.GoogleMeet]: "Google Meet",
    [LocationType.Zoom]: "Zoom Video",
  };

  const _bookingHandler = (event) => {
    const book = async () => {
      setLoading(true);
      setError(false);
      let notes = "";
      if (props.eventType.customInputs) {
        notes = props.eventType.customInputs
          .map((input) => {
            const data = event.target["custom_" + input.id];
            if (data) {
              if (input.type === EventTypeCustomInputType.BOOL) {
                return input.label + "\n" + (data.checked ? "Yes" : "No");
              } else {
                return input.label + "\n" + data.value;
              }
            }
          })
          .join("\n\n");
      }
      if (!!notes && !!event.target.notes.value) {
        notes += "\n\nAdditional notes:\n" + event.target.notes.value;
      } else {
        notes += event.target.notes.value;
      }

      const payload: BookingCreateBody = {
        start: dayjs(date).format(),
        end: dayjs(date).add(props.eventType.length, "minute").format(),
        name: event.target.name.value,
        email: event.target.email.value,
        notes: notes,
        guests: guestEmails,
        eventTypeId: props.eventType.id,
        timeZone: timeZone(),
      };
      if (typeof rescheduleUid === "string") payload.rescheduleUid = rescheduleUid;
      if (typeof router.query.user === "string") payload.user = router.query.user;

      if (selectedLocation) {
        switch (selectedLocation) {
          case LocationType.Phone:
            payload["location"] = event.target.phone.value;
            break;

          case LocationType.InPerson:
            payload["location"] = locationInfo(selectedLocation).address;
            break;

          // Catches all other location types, such as Google Meet, Zoom etc.
          default:
            payload["location"] = selectedLocation;
        }
      }

      telemetry.withJitsu((jitsu) =>
        jitsu.track(telemetryEventTypes.bookingConfirmed, collectPageParameters())
      );

      const content = await createBooking(payload).catch((e) => {
        console.error(e.message);
        setLoading(false);
        setError(true);
      });

      if (content?.id) {
        const params: { [k: string]: any } = {
          date,
          type: props.eventType.id,
          user: props.profile.slug,
          reschedule: !!rescheduleUid,
          name: payload.name,
        };

        if (payload["location"]) {
          if (payload["location"].includes("integration")) {
            params.location = "Web conferencing details to follow.";
          } else {
            params.location = payload["location"];
          }
        }

        const query = stringify(params);
        let successUrl = `/success?${query}`;

        if (content?.paymentUid) {
          successUrl = createPaymentLink(content?.paymentUid, payload.name, date, false);
        }

        await router.push(successUrl);
      } else {
        setLoading(false);
        setError(true);
      }
    };

    event.preventDefault();
    book();
  };

  const bookingHandler = useCallback(_bookingHandler, []);

  return (
    <div>
      <Head>
        <title>
          {rescheduleUid ? "Reschedule" : "Confirm"} your {props.eventType.title} with {props.profile.name} |
          Cal.com
        </title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="max-w-3xl mx-auto my-0 sm:my-24">
        {isReady && (
          <div className="dark:bg-neutral-900 bg-white overflow-hidden border border-gray-200 dark:border-0 sm:rounded-sm">
            <div className="sm:flex px-4 py-5 sm:p-4">
              <div className="sm:w-1/2 sm:border-r sm:dark:border-black">
                <AvatarGroup
                  size={16}
                  items={[{ image: props.profile.image, alt: props.profile.name }].concat(
                    props.eventType.users
                      .filter((user) => user.name !== props.profile.name)
                      .map((user) => ({
                        image: user.avatar,
                        title: user.name,
                      }))
                  )}
                />
                <h2 className="font-cal font-medium dark:text-gray-300 text-gray-500">
                  {props.profile.name}
                </h2>
                <h1 className="text-3xl font-semibold dark:text-white text-gray-800 mb-4">
                  {props.eventType.title}
                </h1>
                <p className="text-gray-500 mb-2">
                  <ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
                  {props.eventType.length} minutes
                </p>
                {props.eventType.price > 0 && (
                  <p className="text-gray-500 mb-1 px-2 py-1 -ml-2">
                    <CreditCardIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
                    <IntlProvider locale="en">
                      <FormattedNumber
                        value={props.eventType.price / 100.0}
                        style="currency"
                        currency={props.eventType.currency.toUpperCase()}
                      />
                    </IntlProvider>
                  </p>
                )}
                {selectedLocation === LocationType.InPerson && (
                  <p className="text-gray-500 mb-2">
                    <LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
                    {locationInfo(selectedLocation).address}
                  </p>
                )}
                <p className="text-green-500 mb-4">
                  <CalendarIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
                  {parseZone(date).format(timeFormat + ", dddd DD MMMM YYYY")}
                </p>
                <p className="dark:text-white text-gray-600 mb-8">{props.eventType.description}</p>
              </div>
              <div className="sm:w-1/2 sm:pl-8 sm:pr-4">
                <form onSubmit={bookingHandler}>
                  <div className="mb-4">
                    <label htmlFor="name" className="block text-sm font-medium dark:text-white text-gray-700">
                      Your name
                    </label>
                    <div className="mt-1">
                      <input
                        type="text"
                        name="name"
                        id="name"
                        required
                        className="shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black block w-full sm:text-sm border-gray-300 rounded-md"
                        placeholder="John Doe"
                        defaultValue={props.booking ? props.booking.attendees[0].name : ""}
                      />
                    </div>
                  </div>
                  <div className="mb-4">
                    <label
                      htmlFor="email"
                      className="block text-sm font-medium dark:text-white text-gray-700">
                      Email address
                    </label>
                    <div className="mt-1">
                      <input
                        type="email"
                        name="email"
                        id="email"
                        required
                        className="shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black block w-full sm:text-sm border-gray-300 rounded-md"
                        placeholder="you@example.com"
                        defaultValue={props.booking ? props.booking.attendees[0].email : ""}
                      />
                    </div>
                  </div>
                  {locations.length > 1 && (
                    <div className="mb-4">
                      <span className="block text-sm font-medium dark:text-white text-gray-700">
                        Location
                      </span>
                      {locations.map((location) => (
                        <label key={location.type} className="block">
                          <input
                            type="radio"
                            required
                            onChange={(e) => setSelectedLocation(e.target.value)}
                            className="location focus:ring-black h-4 w-4 text-black border-gray-300 mr-2"
                            name="location"
                            value={location.type}
                            checked={selectedLocation === location.type}
                          />
                          <span className="text-sm ml-2 dark:text-gray-500">
                            {locationLabels[location.type]}
                          </span>
                        </label>
                      ))}
                    </div>
                  )}
                  {selectedLocation === LocationType.Phone && (
                    <div className="mb-4">
                      <label
                        htmlFor="phone"
                        className="block text-sm font-medium dark:text-white text-gray-700">
                        Phone Number
                      </label>
                      <div className="mt-1">
                        <PhoneInput
                          name="phone"
                          placeholder="Enter phone number"
                          id="phone"
                          required
                          className="shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black block w-full sm:text-sm border-gray-300 rounded-md"
                          onChange={() => {
                            /* DO NOT REMOVE: Callback required by PhoneInput, comment added to satisfy eslint:no-empty-function */
                          }}
                        />
                      </div>
                    </div>
                  )}
                  {props.eventType.customInputs &&
                    props.eventType.customInputs
                      .sort((a, b) => a.id - b.id)
                      .map((input) => (
                        <div className="mb-4" key={"input-" + input.label.toLowerCase}>
                          {input.type !== EventTypeCustomInputType.BOOL && (
                            <label
                              htmlFor={"custom_" + input.id}
                              className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
                              {input.label}
                            </label>
                          )}
                          {input.type === EventTypeCustomInputType.TEXTLONG && (
                            <textarea
                              name={"custom_" + input.id}
                              id={"custom_" + input.id}
                              required={input.required}
                              rows={3}
                              className="shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black block w-full sm:text-sm border-gray-300 rounded-md"
                              placeholder={input.placeholder}
                            />
                          )}
                          {input.type === EventTypeCustomInputType.TEXT && (
                            <input
                              type="text"
                              name={"custom_" + input.id}
                              id={"custom_" + input.id}
                              required={input.required}
                              className="shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black block w-full sm:text-sm border-gray-300 rounded-md"
                              placeholder={input.placeholder}
                            />
                          )}
                          {input.type === EventTypeCustomInputType.NUMBER && (
                            <input
                              type="number"
                              name={"custom_" + input.id}
                              id={"custom_" + input.id}
                              required={input.required}
                              className="shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black block w-full sm:text-sm border-gray-300 rounded-md"
                              placeholder=""
                            />
                          )}
                          {input.type === EventTypeCustomInputType.BOOL && (
                            <div className="flex items-center h-5">
                              <input
                                type="checkbox"
                                name={"custom_" + input.id}
                                id={"custom_" + input.id}
                                className="focus:ring-black h-4 w-4 text-black border-gray-300 rounded mr-2"
                                placeholder=""
                                required={input.required}
                              />
                              <label
                                htmlFor={"custom_" + input.id}
                                className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
                                {input.label}
                              </label>
                            </div>
                          )}
                        </div>
                      ))}
                  {!props.eventType.disableGuests && (
                    <div className="mb-4">
                      {!guestToggle && (
                        <label
                          onClick={toggleGuestEmailInput}
                          htmlFor="guests"
                          className="block text-sm font-medium dark:text-white text-blue-500 mb-1 hover:cursor-pointer">
                          + Additional Guests
                        </label>
                      )}
                      {guestToggle && (
                        <div>
                          <label
                            htmlFor="guests"
                            className="block text-sm font-medium dark:text-white text-gray-700 mb-1">
                            Guests
                          </label>
                          <ReactMultiEmail
                            placeholder="guest@example.com"
                            emails={guestEmails}
                            onChange={(_emails: string[]) => {
                              setGuestEmails(_emails);
                            }}
                            getLabel={(
                              email: string,
                              index: number,
                              removeEmail: (index: number) => void
                            ) => {
                              return (
                                <div data-tag key={index}>
                                  {email}
                                  <span data-tag-handle onClick={() => removeEmail(index)}>
                                    ×
                                  </span>
                                </div>
                              );
                            }}
                          />
                        </div>
                      )}
                    </div>
                  )}
                  <div className="mb-4">
                    <label
                      htmlFor="notes"
                      className="block text-sm font-medium dark:text-white text-gray-700 mb-1">
                      Additional notes
                    </label>
                    <textarea
                      name="notes"
                      id="notes"
                      rows={3}
                      className="shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black block w-full sm:text-sm border-gray-300 rounded-md"
                      placeholder="Please share anything that will help prepare for our meeting."
                      defaultValue={props.booking ? props.booking.description : ""}
                    />
                  </div>
                  <div className="flex items-start space-x-2">
                    {/* TODO: add styling props to <Button variant="" color="" /> and get rid of btn-primary */}
                    <Button type="submit" loading={loading}>
                      {rescheduleUid ? "Reschedule" : "Confirm"}
                    </Button>
                    <Button color="secondary" type="button" onClick={() => router.back()}>
                      Cancel
                    </Button>
                  </div>
                </form>
                {error && (
                  <div className="bg-yellow-50 border-l-4 border-yellow-400 p-4 mt-2">
                    <div className="flex">
                      <div className="flex-shrink-0">
                        <ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" />
                      </div>
                      <div className="ml-3">
                        <p className="text-sm text-yellow-700">
                          Could not {rescheduleUid ? "reschedule" : "book"} the meeting.
                        </p>
                      </div>
                    </div>
                  </div>
                )}
              </div>
            </div>
          </div>
        )}
      </main>
    </div>
  );
};

export default BookingPage;
