import { useState, useCallback } from "react";
import useSWR, { mutate } from "swr";

async function getText(res) {
  try {
    return (await res.text()) || res.statusText;
  } catch (error) {
    return res.statusText;
  }
}

async function getError(res) {
  if (res.headers.get("Content-Type")?.includes("application/json")) {
    const data = await res.json();
    return data.errors[0];
  }
  return { message: await getText(res) };
}

async function fetcher(url) {
  const res = await fetch(url);

  if (res.status === 200) {
    return res.json();
  }
  throw await getError(res);
}

export function useCart() {
  return useSWR("/api/cart", fetcher);
}

export function useAddToCart() {
  const [{ addingToCart, error }, setStatus] = useState({
    addingToCart: false,
  });
  const addToCart = useCallback(async ({ product }) => {
    setStatus({ addingToCart: true });

    const res = await fetch("/api/cart", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ product }),
    });

    // Product added as expected
    if (res.status === 200) {
      setStatus({ addingToCart: false });
      return mutate("/api/cart");
    }

    const error = await getError(res);

    console.error("Adding product to cart failed with:", res.status, error);
    setStatus({ addingToCart: false, error });
  }, []);

  return { addToCart, addingToCart, error };
}

export function useUpdateCart() {
  const [{ updatingCart, error }, setStatus] = useState({
    updatingCart: false,
  });
  const updateCart = useCallback(async ({ product, item }) => {
    setStatus({ updatingCart: true });

    const res = await fetch(
      `/api/cart?itemId=${item.id}`,
      product.quantity < 1
        ? { method: "DELETE" }
        : {
            method: "PUT",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({ product }),
          }
    );

    // Product updated as expected
    if (res.status === 200) {
      setStatus({ updatingCart: false });
      return mutate("/api/cart");
    }

    const error = await getError(res);

    console.error("Update to cart failed with:", res.status, error);
    setStatus({ updatingCart: false, error });
  }, []);

  return { updateCart, updatingCart, error };
}

export function useRemoveFromCart() {
  const { updateCart, updatingCart, error } = useUpdateCart();
  const removeFromCart = async ({ item }) => {
    updateCart({ item, product: { quantity: 0 } });
  };

  return { removeFromCart, removingFromCart: updatingCart, error };
}