"use client";

import type { PopulatedProduct } from "@/services/models/Product";

import ChevronLeftSVG from "@/assets/icons/chevron-left.svg";

import Button from "@/components/Button/Button";

import { formSchema, type FormData } from "@/lib/schemas/NewOrderForm.schema";
import { createGuestOrder } from "@/services/actions/orderAPI";
import type { Cart } from "@/services/models/Cart";
import { zodResolver } from "@hookform/resolvers/zod";
import { useRouter } from "next/navigation";
import { useFieldArray, useForm, useWatch } from "react-hook-form";
import toast from "react-hot-toast";
import Input from "../Input/Input";
import InputGroup from "../InputGroup/InputGroup";
import NewOrderPreview from "../NewOrderPreview/NewOrderPreview";
import OrderItem from "../OrderItem/OrderItem";
import SearchDropdown from "../SearchDropdown/SearchDropdown";
import styles from "./NewOrderForm.module.scss";

export default function NewOrderForm({
  products,
}: {
  products: PopulatedProduct[];
}) {
  const router = useRouter();
  const {
    register,
    control,
    handleSubmit,
    setValue,
    formState: { errors },
  } = useForm({
    resolver: zodResolver(formSchema),
    defaultValues: { items: [] },
  });

  const { fields, append, remove } = useFieldArray({
    control,
    name: "items",
  });

  const formValues = useWatch({ control });

  const searchData = products.map((item) => ({
    label: item.name,
    value: item.slug,
  }));

  const items = (formValues.items ?? []).flatMap((item) => {
    const product = products.find((product) =>
      product.variants.some((variant) => variant.sku === item.sku),
    );

    const variant = product?.variants.find(
      (variant) => variant.sku === item.sku,
    );

    if (!product || !variant || !item.quantity) return [];

    return [
      {
        name: product.name,
        sku: variant.sku,
        quantity: item.quantity,
        price: variant.price,
        productId: { productId: product._id, variants: product.variants },
      },
    ];
  });

  async function onSubmit(data: FormData) {
    const promise = async () => {
      if (!previewOrder?.items)
        throw new Error(
          "Failed to create an order: items list cannot be empty.",
        );

      await createGuestOrder({
        name: data.name,
        email: data.email,
        phoneNumber: data.phoneNumber,
        address: data.address,
        items: previewOrder.items.map((item) => ({
          ...item,
          productId: item.productId.productId,
        })),
        totals: previewOrder.totals,
      });
    };

    await toast.promise(promise, {
      loading: "Загрузка...",
      success: `Заказ успешно добавлен.`,
      error: "Упс! Что-то пошло не так :(",
    });

    router.push("/dashboard/orders");
  }

  function handleSelectProduct(item: { label: string; value: string }) {
    const product = products.find((product) => product.slug === item.value)
      ?.variants[0];

    if (!product) return;

    append({ sku: product.sku, quantity: 1 });
  }

  function calculateTotals(items: Cart["items"]): Cart["totals"] {
    const sub = items.reduce(
      (accum, item) => accum + item.price * item.quantity,
      0,
    );
    const discountPercent =
      sub >= 300000 ? 10 : sub >= 250000 ? 5 : sub >= 150000 ? 3.5 : 0;
    const discount = Math.round((discountPercent / 100) * sub);
    const ship =
      sub >= 350000 ? 0 : sub >= 300000 ? 7350 : sub >= 200000 ? 5500 : 4900;

    return {
      sub,
      discount,
      ship,
      grand: sub - discount + ship,
    };
  }

  function buildPreviewOrder() {
    const { name, email, phoneNumber, address } = formValues;

    if (
      !name ||
      !email ||
      !phoneNumber ||
      !address?.line1 ||
      !address.city ||
      !address.zip ||
      items.length === 0
    ) {
      return null;
    }

    return {
      name,
      email,
      phoneNumber,
      address: {
        line1: address.line1,
        city: address.city,
        zip: address.zip,
      },
      totals: calculateTotals(items),
      items,
    };
  }

  const previewOrder = buildPreviewOrder();

  return (
    <div className={styles["new-order-form"]}>
      <div className={styles["new-order-form__header"]}>
        <div className={styles["new-order-form__header-left"]}>
          <Button icon={ChevronLeftSVG} href="/dashboard/orders" />

          <span className={styles["new-order-form__heading"]}>
            Оформление Заказа
          </span>
        </div>

        <Button variant="primary" onClick={() => void handleSubmit(onSubmit)()}>
          Добавить
        </Button>
      </div>

      <form
        onSubmit={(event) => {
          event.preventDefault();
        }}
        className={styles["new-order-form__form"]}
      >
        <div className={styles["new-order-form__section"]}>
          <span className={styles["new-order-form__section-heading"]}>
            Общая информация
          </span>

          <div className={styles["new-order-form__section-body"]}>
            <InputGroup label="Заказчик">
              <Input
                label="Полное имя"
                type="text"
                error={errors.name?.message}
                {...register("name", {
                  required: "Обязательное поле.",
                })}
                className={styles["new-order-form__input"]}
              />

              <Input
                label="Электронная почта"
                type="text"
                error={errors.email?.message}
                {...register("email", {
                  required: "Обязательное поле.",
                })}
                className={styles["new-order-form__input"]}
              />

              <Input
                label="Номер телефона"
                type="text"
                error={errors.phoneNumber?.message}
                {...register("phoneNumber", {
                  required: "Обязательное поле.",
                })}
                className={styles["new-order-form__input"]}
              />
            </InputGroup>

            <InputGroup label="Адрес доставки">
              <Input
                label="Улица"
                type="text"
                error={errors.address?.line1?.message}
                {...register("address.line1", {
                  required: "Обязательное поле.",
                })}
                className={styles["new-order-form__input"]}
              />

              <Input
                label="Город"
                type="text"
                error={errors.address?.city?.message}
                {...register("address.city", {
                  required: "Обязательное поле.",
                })}
                className={styles["new-order-form__input"]}
              />

              <Input
                label="Почтовый индекс"
                inputMode="numeric"
                pattern="[0-9]*"
                error={errors.address?.zip?.message}
                {...register("address.zip", {
                  required: "Обязательное поле.",
                  onChange(e) {
                    e.target.value = e.target.value.replace(/\D/g, "");
                  },
                })}
                className={styles["new-order-form__input"]}
              />
            </InputGroup>
          </div>
        </div>

        <div className={styles["new-order-form__section"]}>
          <NewOrderPreview order={previewOrder} />
        </div>

        <div className={styles["new-order-form__section"]}>
          <span className={styles["new-order-form__section-heading"]}>
            Состав заказа
          </span>

          <div className={styles["new-order-form__section-body"]}>
            <SearchDropdown
              name="query"
              data={searchData}
              placeholder="Выберите продукт"
              onSelect={handleSelectProduct}
            />

            <table className={styles["new-order-form__table"]}>
              <thead>
                <tr>
                  <th></th>
                  <th>Продукт</th>
                  <th>Идентификатор</th>
                  <th>Цвет</th>
                  <th>Цена</th>
                  <th>Количество</th>
                  <th>Сумма</th>
                </tr>
              </thead>

              <tbody>
                {fields.map((field, index) => {
                  const product = products.find((product) =>
                    product.variants.some(
                      (variant) => variant.sku === field.sku,
                    ),
                  );

                  if (!product) return;

                  return (
                    <OrderItem
                      key={field.id}
                      index={index}
                      control={control}
                      register={register}
                      setValue={setValue}
                      product={product}
                      isRemovable={fields.length > 1}
                      onRemove={() => {
                        remove(index);
                      }}
                    />
                  );
                })}
              </tbody>
            </table>

            {errors.items?.message && (
              <p className={styles["new-order-form__error-message"]}>
                Состав заказа не может быть пустым.
              </p>
            )}
          </div>
        </div>
      </form>
    </div>
  );
}
