"use client";

import type { CartItem } from "generated/prisma";
import { IMAGES_MANIFEST } from "next/dist/shared/lib/constants";
import { useEffect, useState, useCallback } from "react";

type Cart = {
  cartItems: {
    itemId: string;
    quantity: number;
  }[];
};

type UserResponse = {
  id: string;
  name: string | null;
  carts: Cart[];
  adresses: string[];
  balance: number;
};

type CartViewItem = {
  id: string;
  name: string;
  actualQuantity: number;
  itemAmount: number;
  stock: number;
  price: number;
};

type ApiItem = {
  id: string;
  item_name: string;
  amount: number;
  price: number;
  enabled: boolean;
  shop: {
    label: string;
  };
  item: {
    stock: number;
  };
};

const formatName = (name: string) => {
  const parts = name.split(":");
  if (!parts[1]) return "";
  return parts[1]
    .split("_")
    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
    .join(" ");
};

const getImage = (name: string) => {
  const [mod, item] = name.split(":");
  return `/textures/${mod}/${item}.png`;
};

type CartButtonProps = {
  userData: UserResponse | null;
  reloadUser: () => Promise<void>;
  loading: boolean;
};

// Add at top of CartButton component
type DraggingState = {
  itemId: string;
  quantity: number;
  max: number;
  rect: DOMRect;
} | null;

async function buyItems(cart: CartViewItem[], address: string) {
  await fetch("/api/buy", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ cart, address }),
  });
}

export default function CartButton({
  userData,
  reloadUser,
  loading,
}: CartButtonProps) {
  const [cartItems, setCartItems] = useState<CartViewItem[]>([]);
  const [totalQuantity, setTotalQuantity] = useState(0);
  const [isOpen, setIsOpen] = useState(false);
  const [selectedAddress, setSelectedAddress] = useState<string>(
    userData?.adresses?.[0] ?? "",
  );
  const [dragging, setDragging] = useState<DraggingState>(null);
  const [sliderActive, setSliderActive] = useState<string | null>(null);
  const [holdTimeout, setHoldTimeout] = useState<NodeJS.Timeout | null>(null);

  useEffect(() => {
    if (!userData) return;

    const fetchItems = async () => {
      const res = await fetch("/api/sellable");
      const items = (await res.json()) as ApiItem[];
      const itemMap = new Map(items.map((i) => [i.id, i]));

      let total = 0;
      const collected: CartViewItem[] = [];

      for (const cart of userData.carts ?? []) {
        for (const cartItem of cart.cartItems) {
          const item = itemMap.get(cartItem.itemId);
          if (!item) continue;
          const actualQuantity = cartItem.quantity * item.amount;
          total += actualQuantity;
          collected.push({
            id: item.id,
            name: item.item_name,
            actualQuantity,
            itemAmount: item.amount,
            stock: item.item.stock,
            price: item.price,
          });
        }
      }
      if (!selectedAddress) {
        setSelectedAddress(userData.adresses?.[0] ?? "");
      }
      setCartItems(collected);
      setTotalQuantity(total);
    };

    void fetchItems();
  }, [userData]);

  const getItemSubtotal = (item: CartViewItem) => {
    return (item.price * item.actualQuantity) / item.itemAmount;
  };

  const cartTotalPrice = cartItems.reduce(
    (sum, item) => sum + getItemSubtotal(item),
    0,
  );

  const formatPrice = (value: number) =>
    value.toLocaleString(undefined, {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2,
    });

  // Remove item function (negative quantity)
  const removeItem = async (id: string, quantity: number) => {
    try {
      await fetch("/api/cart", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ id, quantity: -quantity }),
      });
      await reloadUser();
    } catch (err) {
      console.error("Failed to remove item", err);
    }
  };

  // Drag/hold logic
  const handleMouseDown = (e: React.MouseEvent, item: CartViewItem) => {
    e.preventDefault();

    const rect = e.currentTarget.getBoundingClientRect();

    const timeout = setTimeout(() => {
      setSliderActive(item.id);
      setDragging({
        itemId: item.id,
        quantity: 1,
        max: item.actualQuantity / item.itemAmount,
        rect,
      });
    }, 300); // hold threshold
    setHoldTimeout(timeout);
  };

  const handleMouseUp = (e: React.MouseEvent, item: CartViewItem) => {
    e.preventDefault();
    if (holdTimeout) {
      clearTimeout(holdTimeout);
      setHoldTimeout(null);
    }
    if (!sliderActive) {
      void removeItem(item.id, 1); // quick click removes 1
    }
  };

  const handleMouseMove = useCallback(
    (e: MouseEvent) => {
      if (!dragging) return;
      const { rect, max } = dragging;
      let relativeX = e.clientX - rect.left;
      relativeX = Math.max(0, Math.min(relativeX, rect.width));
      const quantity = Math.max(1, Math.round((relativeX / rect.width) * max));
      setDragging({ ...dragging, quantity });
    },
    [dragging],
  );

  const handleMouseRelease = useCallback(async () => {
    if (dragging) {
      const { itemId, quantity } = dragging;
      setDragging(null);
      setSliderActive(null);
      await removeItem(itemId, quantity);
    }
  }, [dragging]);

  useEffect(() => {
    if (!dragging) return;
    window.addEventListener("mousemove", handleMouseMove);
    window.addEventListener("mouseup", handleMouseRelease);
    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
      window.removeEventListener("mouseup", handleMouseRelease);
    };
  }, [dragging, handleMouseMove, handleMouseRelease]);

  const buyDisabled =
    cartItems.length === 0 ||
    cartItems.some((item) => item.stock < item.actualQuantity) ||
    !userData?.balance ||
    cartTotalPrice > userData.balance;

  const buyDisabledReason = buyDisabled
    ? cartItems.some((item) => item.stock === 0)
      ? "Out of stock"
      : cartItems.some((item) => item.stock < item.actualQuantity)
        ? "Not enough stock"
        : !userData?.balance || cartTotalPrice > userData.balance
          ? "Insufficient balance"
          : "No items in cart"
    : null;

  return (
    <>
      {/* CART BUTTON */}
      <button
        className="relative rounded-full bg-white/10 px-4 py-2 font-semibold transition hover:bg-white/20"
        disabled={loading}
        onClick={() => setIsOpen(true)}
      >
        <img src="/icons/cart.svg" alt="Cart Icon" className="h-6 w-6" />
        {totalQuantity > 0 && (
          <span className="absolute -top-1 -right-1 flex h-5 min-w-5 items-center justify-center rounded-full bg-red-500 px-1 text-xs font-bold text-white">
            {totalQuantity}
          </span>
        )}
      </button>

      {/* OVERLAY */}
      {isOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center">
          <div
            className="absolute inset-0 bg-black/50 backdrop-blur-sm"
            onClick={() => setIsOpen(false)}
          />

          <div className="relative z-10 w-full max-w-md rounded-xl bg-neutral-900 p-6 text-white shadow-xl">
            <h2 className="mb-4 text-xl font-bold">Your Cart</h2>

            {cartItems.length === 0 ? (
              <p className="text-neutral-400">Cart is empty</p>
            ) : (
              <ul className="space-y-3">
                {cartItems.map((item) => (
                  <li
                    className="flex items-center justify-between rounded-lg bg-white/5 px-3 py-2"
                    key={item.id}
                  >
                    <div className="flex items-center gap-3">
                      <img
                        src={getImage(item.name)}
                        alt={item.name}
                        className="h-8 w-8 rounded-full"
                      />
                      <div>
                        <p className="flex items-center gap-1 font-medium">
                          {formatName(item.name)}
                          {item.actualQuantity > item.stock && (
                            <span className="font-bold text-red-500">!</span>
                          )}
                        </p>
                        <p className="text-sm text-neutral-400">
                          Qty: {item.actualQuantity} · Price: $
                          {formatPrice(item.price)}
                        </p>
                        <p className="text-sm font-semibold text-green-400">
                          Subtotal: ${formatPrice(getItemSubtotal(item))}
                        </p>
                      </div>
                    </div>

                    {/* Remove button with hold/slider */}
                    <div className="relative flex flex-col items-end">
                      <button
                        onMouseDown={(e) => handleMouseDown(e, item)}
                        onMouseUp={(e) => handleMouseUp(e, item)}
                        className="rounded bg-red-500 px-3 py-1 text-sm font-semibold hover:bg-red-600"
                      >
                        Remove
                      </button>

                      {sliderActive === item.id && dragging && (
                        <div className="pointer-events-none absolute inset-0 z-30 flex items-center justify-center">
                          <div className="relative h-full w-full rounded">
                            <div className="relative h-7 w-full rounded bg-white/20">
                              <div className="absolute top-0 left-0 h-full w-full rounded bg-gray-400" />
                              <div
                                className="absolute top-0 left-0 h-full rounded bg-red-500 transition-transform duration-300"
                                style={{
                                  width: `${(dragging.quantity / dragging.max) * 100}%`,
                                }}
                              />
                              <span className="text-md absolute top-0 right-2 font-bold text-white">
                                x{dragging.quantity * item.itemAmount}
                              </span>
                            </div>
                          </div>
                        </div>
                      )}
                    </div>
                  </li>
                ))}
              </ul>
            )}

            <div className="mt-4 flex items-center justify-between rounded-lg bg-white/10 px-4 py-3">
              <span className="text-lg font-semibold">Total</span>
              <span className="text-lg font-bold text-green-400">
                ${formatPrice(cartTotalPrice)}
              </span>
            </div>

            {/* ADDRESS SELECT */}
            {userData?.adresses && userData.adresses.length > 0 && (
              <div className="mt-4">
                <label
                  htmlFor="address"
                  className="mb-2 block text-sm font-medium text-neutral-300"
                >
                  Select Delivery Address
                </label>
                <select
                  id="address"
                  className="w-full rounded-lg border border-neutral-700 bg-neutral-800 p-2 text-white focus:border-green-500 focus:ring-1 focus:ring-green-500"
                  value={selectedAddress}
                  onChange={(e) => setSelectedAddress(e.target.value)}
                >
                  {userData.adresses.map((addr, idx) => (
                    <option key={idx} value={addr}>
                      {addr}
                    </option>
                  ))}
                </select>
              </div>
            )}

            <button
              className={`mt-6 w-full rounded-lg py-3 font-bold text-black ${buyDisabled ? "cursor-not-allowed bg-gray-400" : "bg-green-500 hover:bg-green-600"}`}
              onClick={() => {
                if (
                  !selectedAddress ||
                  selectedAddress === "" ||
                  cartItems.length === 0
                )
                  return;
                void buyItems(cartItems, selectedAddress);
              }}
              disabled={buyDisabled}
            >
              Buy
            </button>
            {buyDisabled && buyDisabledReason && (
              <p className="mt-3 text-center text-sm font-medium text-red-400">
                {buyDisabledReason}
              </p>
            )}
          </div>
        </div>
      )}
    </>
  );
}
