"use client";

import { useEffect, useRef, useState } from "react";

import axios from "axios";

import Cookies from "js-cookie";

import Image from "next/image";

import { z } from "zod";

import { zodResolver } from "@hookform/resolvers/zod";

import { Controller, useForm } from "react-hook-form";

import { Button } from "@/components/shadcnui/button";

import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
} from "@/components/shadcnui/card";

import {
  Field,
  FieldError,
  FieldGroup,
  FieldLabel,
} from "@/components/shadcnui/field";

import { Input } from "@/components/shadcnui/input";

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/shadcnui/select";

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/shadcnui/table";

import toast, { Toaster } from "react-hot-toast";

const productSchema = z.object({
  name: z.string().min(2, "Name required"),

  categoryId: z.string().min(1, "Category required"),

  shortDescription: z.string().min(2, "Short description required"),

  description: z.string().min(2, "Description required"),

  sku: z.string().min(2, "SKU required"),

  stock: z.string().min(1, "Stock required"),

  price: z.string().min(1, "Price required"),

  priceUnit: z.string().min(1, "Price unit required"),

  packOf: z.string().min(1, "Pack required"),

  priceTag: z.string().min(1, "Price tag required"),

  pImage: z.any().optional(),
});

type ProductFormType = z.infer<typeof productSchema>;

interface CategoryType {
  _id: string;

  name: string;
}

interface ProductType {
  _id: string;

  name: string;

  shortDescription: string;

  description: string;

  sku: string;

  stock: number;

  price: number;

  priceUnit: string;

  packOf: string;

  priceTag: string;

  imageUrl: string;

  isActive: boolean;

  categoryId: {
    _id: string;

    name: string;
  };
}

const ProductForm = () => {
  const token = Cookies.get("kero_token");

  const [loading, setLoading] = useState(false);

  const [image, setImage] = useState<File | null>(null);
  const [imagePreview, setImagePreview] = useState("");

  const [editId, setEditId] = useState<string | null>(null);

  const [products, setProducts] = useState<ProductType[]>([]);

  const [categories, setCategories] = useState<CategoryType[]>([]);
  const imageRef = useRef<HTMLInputElement | null>(null);

  const [search, setSearch] = useState("");

  const [page, setPage] = useState(1);

  const [totalPages, setTotalPages] = useState(1);

  /*
   * Abort controllers
   *
   * These are used only for GET requests.
   * If another request starts before the previous request finishes,
   * the previous request will be cancelled.
   */
  const productsAbortControllerRef = useRef<AbortController | null>(null);

  const categoriesAbortControllerRef = useRef<AbortController | null>(null);

  const form = useForm<ProductFormType>({
    resolver: zodResolver(productSchema),

    defaultValues: {
      name: "",

      categoryId: "",

      shortDescription: "",

      description: "",

      sku: "",

      stock: "",

      price: "",

      priceUnit: "",

      packOf: "",

      priceTag: "",
      pImage: undefined,
    },
  });

  const getAllCategories = async () => {
    /*
     * Cancel previous categories request if it is still running.
     */
    if (categoriesAbortControllerRef.current) {
      categoriesAbortControllerRef.current.abort();
    }

    const controller = new AbortController();

    categoriesAbortControllerRef.current = controller;

    try {
      const response = await axios.get(
        `${process.env.NEXT_PUBLIC_API_BASE_URL}/categories/all_Categories`,
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },

          signal: controller.signal,
        },
      );

      if (response.data.success) {
        setCategories(response.data.categories);
      }
    } catch (error) {
      /*
       * Ignore cancelled requests.
       *
       * This prevents cancellation from being treated
       * as a real API error.
       */
      if (axios.isCancel(error)) {
        return;
      }

      console.log(error);
    }
  };

  const getAllProducts = async (currentPage = page, currentSearch = search) => {
    /*
     * Cancel the previous products request if it is still running.
     */
    if (productsAbortControllerRef.current) {
      productsAbortControllerRef.current.abort();
    }

    const controller = new AbortController();

    productsAbortControllerRef.current = controller;

    try {
      const response = await axios.get(
        `${process.env.NEXT_PUBLIC_API_BASE_URL}/products/admin?page=${currentPage}&limit=15&search=${currentSearch}`,
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },

          signal: controller.signal,
        },
      );

      /*
       * Make sure this request is still the latest request
       * before updating the UI.
       */
      if (controller.signal.aborted) {
        return;
      }

      if (response.data.success) {
        setProducts(response.data.products || []);

        setPage(currentPage);

        setTotalPages(Math.ceil((response.data.total || 0) / 15) || 1);
      }
    } catch (error) {
      /*
       * Ignore cancelled requests.
       *
       * When the user quickly changes pages or leaves the page,
       * the old request can be cancelled intentionally.
       */
      if (axios.isCancel(error)) {
        return;
      }

      console.log(error);

      toast.error("Failed to fetch products");
    }
  };

  useEffect(() => {
    getAllCategories();

    getAllProducts(page, search);
  }, [page]);

  useEffect(() => {
    if (search.trim() === "") {
      setPage(1);

      getAllProducts(1, "");
    }
  }, [search]);

  /*
   * Cancel pending GET requests when the product page
   * is removed/unmounted.
   *
   * This is important when rapidly switching between
   * dashboard sidebar pages.
   */
  useEffect(() => {
    return () => {
      if (productsAbortControllerRef.current) {
        productsAbortControllerRef.current.abort();
      }

      if (categoriesAbortControllerRef.current) {
        categoriesAbortControllerRef.current.abort();
      }
    };
  }, []);

  const onSubmit = async (values: ProductFormType) => {
    try {
      const duplicateProduct = products.some(
        (item) =>
          item.name.toLowerCase().trim() === values.name.toLowerCase().trim() &&
          item._id !== editId,
      );

      if (duplicateProduct) {
        toast.error("Product already exists");

        return;
      }

      if (!image && !editId && !imagePreview) {
        toast.error("Product image required");

        return;
      }

      setLoading(true);

      const formData = new FormData();

      formData.append("name", values.name);

      formData.append("categoryId", values.categoryId);

      formData.append("shortDescription", values.shortDescription);

      formData.append("description", values.description);

      formData.append("sku", values.sku);

      formData.append("stock", values.stock);

      formData.append("price", String(Number(values.price.replace(/,/g, ""))));

      formData.append("priceUnit", values.priceUnit);

      formData.append("packOf", values.packOf);

      formData.append("priceTag", values.priceTag);

      if (image) {
        formData.append("image", image);
      }

      if (editId) {
        await axios.put(
          `${process.env.NEXT_PUBLIC_API_BASE_URL}/products/${editId}`,
          formData,
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          },
        );

        toast.success("Product updated!");
      } else {
        await axios.post(
          `${process.env.NEXT_PUBLIC_API_BASE_URL}/products`,
          formData,
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          },
        );

        toast.success("Product created!");
      }

      form.reset();

      setImage(null);

      setImagePreview("");

      setEditId(null);

      if (imageRef.current) {
        imageRef.current.value = "";
      }

      getAllProducts();
    } catch (error) {
      console.log(error);

      if (axios.isAxiosError(error)) {
        const message =
          error.response?.data?.message || error.response?.data?.error || "";

        if (
          message.toLowerCase().includes("duplicate") ||
          message.toLowerCase().includes("exists")
        ) {
          toast.error("Product already exists");
        } else {
          toast.error(message || "Unable to save product");
        }
      } else {
        toast.error("Something went wrong");
      }
    } finally {
      setLoading(false);
    }
  };

  const handleDelete = async (id: string) => {
    try {
      await axios.delete(
        `${process.env.NEXT_PUBLIC_API_BASE_URL}/products/${id}`,
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        },
      );

      toast.error("Product deleted!");

      getAllProducts();
    } catch (error) {
      console.log(error);
    }
  };

  const handleEdit = (product: ProductType) => {
    setEditId(product._id);

    form.setValue("name", product.name);

    form.setValue("categoryId", product.categoryId?._id || "");

    form.setValue("shortDescription", product.shortDescription);

    form.setValue("description", product.description);

    form.setValue("sku", product.sku);

    form.setValue("stock", String(product.stock));

    form.setValue("price", String(product.price));

    form.setValue("priceUnit", product.priceUnit);

    form.setValue("packOf", product.packOf);

    form.setValue("priceTag", product.priceTag);

    setImage(null);

    if (imageRef.current) {
      imageRef.current.value = "";
    }

    setImagePreview(`http://app.keroindia.com${product.imageUrl}`);

    toast.success("Product loaded for edit");

    window.scrollTo({
      top: 0,
      behavior: "smooth",
    });
  };

  return (
    <div className="mt-6 space-y-8">
      <Toaster
        position="top-center"
        reverseOrder={false}
      />

      <Card>
        <CardHeader>
          <CardTitle>{editId ? "Edit Product" : "Create Product"}</CardTitle>
        </CardHeader>

        <CardContent>
          <form
            onSubmit={form.handleSubmit(onSubmit)}
            className="space-y-5">
            <FieldGroup>
              <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
                <Controller
                  name="name"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field data-invalid={fieldState.invalid}>
                      <FieldLabel>Product Name</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Enter product name"
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="categoryId"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Category</FieldLabel>

                      <Select
                        value={field.value}
                        onValueChange={field.onChange}>
                        <SelectTrigger>
                          <SelectValue
                            placeholder="Select category"
                            aria-invalid={fieldState.invalid}
                          />
                        </SelectTrigger>

                        <SelectContent>
                          {categories.map((category) => (
                            <SelectItem
                              key={category._id}
                              value={category._id}>
                              {category.name}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="shortDescription"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Short Description</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Short description"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="description"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Description</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Description"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="sku"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>SKU</FieldLabel>

                      <Input
                        {...field}
                        placeholder="SKU"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="stock"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Stock</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Stock"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="price"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Price</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Price"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="priceUnit"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Price Unit</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Price Unit"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="packOf"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Pack Of</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Pack Of"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="priceTag"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field>
                      <FieldLabel>Price Tag</FieldLabel>

                      <Input
                        {...field}
                        placeholder="Price Tag"
                        aria-invalid={fieldState.invalid}
                      />

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />

                <Controller
                  name="pImage"
                  control={form.control}
                  render={({ field, fieldState }) => (
                    <Field data-invalid={fieldState.invalid}>
                      <FieldLabel>Product Image</FieldLabel>

                      {!imagePreview && (
                        <Input
                          ref={imageRef}
                          type="file"
                          accept="image/*"
                          onChange={(e) => {
                            const file = e.target.files?.[0];

                            if (file) {
                              setImage(file);

                              setImagePreview(URL.createObjectURL(file));

                              field.onChange(file);
                            }
                          }}
                        />
                      )}

                      {imagePreview && (
                        <div className="space-y-3">
                          <Image
                            src={imagePreview}
                            unoptimized
                            alt="preview"
                            width={180}
                            height={180}
                            className="rounded-md border object-cover"
                          />

                          <Button
                            type="button"
                            variant="outline"
                            onClick={() => {
                              setImagePreview("");

                              setImage(null);

                              if (imageRef.current) {
                                imageRef.current.click();
                              }
                            }}>
                            Change Image
                          </Button>
                        </div>
                      )}

                      {fieldState.invalid && (
                        <FieldError errors={[fieldState.error]} />
                      )}
                    </Field>
                  )}
                />
              </div>
            </FieldGroup>

            <Button
              type="submit"
              disabled={loading}>
              {loading ?
                "Saving..."
              : editId ?
                "Update Product"
              : "Create Product"}
            </Button>
          </form>
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>All Products</CardTitle>
        </CardHeader>

        <CardContent className="overflow-x-auto">
          <Field
            className="w-full pb-4"
            orientation={"horizontal"}>
            <Input
              placeholder="Search product"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
            />

            <Button
              type="button"
              onClick={() => {
                setPage(1);

                getAllProducts(1, search.trim());
              }}>
              Search
            </Button>

            <Button
              type="button"
              variant="outline"
              onClick={() => {
                setSearch("");

                setPage(1);

                getAllProducts(1, "");
              }}>
              Reset
            </Button>
          </Field>

          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>Image</TableHead>

                <TableHead>Name</TableHead>

                <TableHead>Category</TableHead>

                <TableHead>Price</TableHead>

                <TableHead>Stock</TableHead>

                <TableHead>SKU</TableHead>

                <TableHead>Price Tag</TableHead>

                <TableHead>Actions</TableHead>
              </TableRow>
            </TableHeader>

            <TableBody>
              {products.map((item) => (
                <TableRow key={item._id}>
                  <TableCell>
                    <Image
                      src={`http://app.keroindia.com${item.imageUrl}`}
                      unoptimized
                      alt={item.name}
                      width={50}
                      height={50}
                      className="rounded-md object-cover"
                    />
                  </TableCell>

                  <TableCell>{item.name}</TableCell>

                  <TableCell>{item.categoryId?.name || "-"}</TableCell>

                  <TableCell>₹ {item.price}</TableCell>

                  <TableCell>{item.stock}</TableCell>

                  <TableCell>{item.sku}</TableCell>

                  <TableCell>{item.priceTag}</TableCell>

                  <TableCell>
                    <div className="flex gap-2">
                      <Button
                        size="sm"
                        type="button"
                        onClick={() => handleEdit(item)}>
                        Edit
                      </Button>

                      <Button
                        size="sm"
                        type="button"
                        variant="destructive"
                        onClick={() => handleDelete(item._id)}>
                        Delete
                      </Button>
                    </div>
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>

          {/* pagination */}
          <div className="mt-5 flex items-center justify-center gap-4">
            <Button
              type="button"
              variant="outline"
              disabled={page === 1}
              onClick={() => setPage((prev) => prev - 1)}>
              Previous
            </Button>

            <span>
              Page {page} of {totalPages}
            </span>

            <Button
              type="button"
              variant="outline"
              disabled={page >= totalPages}
              onClick={() => setPage((prev) => prev + 1)}>
              Next
            </Button>
          </div>
        </CardContent>
      </Card>
    </div>
  );
};

export default ProductForm;
