"use client";
import { useState, useEffect } from "react";
import InventoryItemView from "./Components/Inventory/InventoryItemView";
import StakingSourcesView from "./Components/Staking/StakingSourcesView";
import BankAccountsView from "./Components/Accounts/AccountsView";
import StoreItemView from "./Components/Store/StoreItemView";
import NotificationPopover from "./Components/NotificationPopover";
import {
  IInventoryItem,
  IStakingSource,
  IBankAccount,
  IStake,
  IConversionPair,
  Notification,
  IGameConfig,
  IStoreItem,
} from "typings";
import Navbar from "./Components/Navigation/Navbar";
import NavbarVertical from "./Components/Navigation/NavbarVertical";

export default function Home() {
  const [inventoryItems, setInventoryItems] = useState<
    IInventoryItem[] | null | undefined
  >([]);
  const [stakingSources, setStakingSources] = useState<IStakingSource[] | null>(
    []
  );
  const [bankAccount, setBankAccount] = useState<IBankAccount>();
  const [userStakes, setUserStakes] = useState<IStake[]>([]);
  const [userId, setUserId] = useState<string>("");
  const [notification, setNotification] = useState<Notification | null>(null);
  const [notificationTime, setNotificationTime] = useState(30);
  const [storeItems, setStoreItems] = useState<IStoreItem[] | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [activeComponent, setActiveComponent] = useState("inventoryitemview");
  const [gameConfig, setGameConfig] = useState<IGameConfig>();

  const isOwned = (storeItemId: number) => {
    if (inventoryItems && inventoryItems?.length > 0) {
      return inventoryItems?.some((item) => item.storeItem.id == storeItemId);
    } else {
      return false;
    }
  };

  const fetchInventoryItems = async () => {
    const response = await fetch(`/api/user/${userId}/inventory-items`);
    const DBInventoryItems = await response.json();

    // Calling the endpoint here because state might not be ready
    const gameConfig = await fetch(`/api/get-game-config`);
    const gameConfigData = await gameConfig.json();

    const updatedInventoryItems = DBInventoryItems.inventoryItems.map(
      (invItem: IInventoryItem) => {
        return {
          ...invItem,
          storeItem: gameConfigData.storeItems?.find(
            (item: IStoreItem) => item.id === invItem.storeItemId
          ),
        };
      }
    );

    setInventoryItems(updatedInventoryItems);
  };

  const fetchStoreItems = async () => {
    const response = await fetch(`/api/get-game-config`);
    const data = await response.json();
    setGameConfig(data);
    setStoreItems(data.storeItems);
  };

  const fetchStakingSources = async () => {
    const response = await fetch(`/api/user/${userId}/staking-sources`);
    const sources = await response.json();
    setStakingSources(sources.stakingSources);
  };

  const fetchStakes = async () => {
    const response = await fetch(`/api/user/${userId}/stakes`);
    const stakes = await response.json();
    setUserStakes(
      stakes.stakes.map((stake: IStake) => ({
        ...stake,
        unclaimed: stake.unclaimed,
      }))
    );
  };

  const fetchBankAccount = async () => {
    const response = await fetch(`/api/user/${userId}/account`);
    const bankAccount = await response.json();
    setBankAccount(bankAccount);
  };

  useEffect(() => {
    if (userId === "") return;
    fetchBankAccount();
    fetchStakingSources();
    fetchInventoryItems();
    fetchStakes();
    fetchStoreItems();
    setIsLoading(false);
  }, [userId]);

  // Update data
  useEffect(() => {
    if (storeItems) {
      const updatedStoreItems = storeItems.map((storeItem) => {
        return {
          ...storeItem,
          isOwned: isOwned(storeItem.id),
        };
      });
      updatedStoreItems && setStoreItems(updatedStoreItems);
    }
  }, [inventoryItems]);

  useEffect(() => {
    if (notification) {
      const intervalId = setInterval(() => {
        setNotificationTime((prev) => prev - 1);
      }, 1000);
      if (notificationTime === 0) {
        setNotification(null);
        clearInterval(intervalId);
        setNotificationTime(30);
      }

      return () => {
        clearInterval(intervalId);
      };
    }
  }, [notification, notificationTime]);

  const claimStake = async (stakingEventId: number) => {
    const response = await fetch(`/api/user/${userId}/stakes/claim`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ stakingEventId: stakingEventId }),
    });
    if (!response.ok) {
      const error = await response.text();
      setNotification({ message: error, type: "Error" });
    }
    if (response.status == 200) {
      const data = await response.json();
      setNotification({
        message: `You've successfully claimed`,
        type: "Success",
      });

      fetchStakes();
      fetchStakingSources();
      fetchInventoryItems();
      fetchBankAccount();
    }
  };

  const startStake = async (
    inventoryItemId: string,
    storeItemId: number,
    wellId: string
  ) => {
    const response = await fetch(`/api/user/${userId}/stakes/start`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        inventoryItemId: inventoryItemId,
        storeItemId,
        wellId: wellId,
      }),
    });
    if (!response.ok) {
      const error = await response.text();
      setNotification({ message: error, type: "Error" });
    }
    if (response.status == 200) {
      const data = await response.json();
      setNotification({
        message: `You've successfully staked`,
        type: "Success",
      });
      fetchStakes();
      fetchStakingSources();
    }
  };

  const sellResource = async (pairs: IConversionPair[]) => {
    const response = await fetch(`/api/user/${userId}/account`, {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        pairs: pairs,
      }),
    });

    if (!response.ok) {
      const error = await response.text();
      setNotification({ message: error, type: "Error" });
    }
    if (response.status == 200) {
      const data = await response.json();
      setNotification({
        message: `You've received ${data[0].returnAmount} $MoonBucks`,
        type: "Success",
      });
      fetchBankAccount();
    }
  };

  const buyStoreItem = async (storeItemId: number) => {
    console.log(`Buying item with id ${storeItemId}`);
    try {
      const response = await fetch(`/api/user/${userId}/inventory-items`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          storeItemId: storeItemId,
        }),
      });

      if (!response.ok) {
        const error = await response.text();
        setNotification({ message: error, type: "Error" });
        return;
      }

      const data = await response.json();

      if (response.status == 200) {
        // Return success message
        setNotification({
          message: "Item has been purchased",
          type: "Success",
        });
        fetchInventoryItems();
        fetchBankAccount();
      }
    } catch (error) {
      if (error instanceof Error) {
        setNotification({ message: error.message, type: "Error" });
      } else {
        setNotification({ message: "An unknown error occured", type: "Error" });
      }
    }
  };

  const upgradeInventoryItem = async (
    inventoryItemId: string,
    storeItemId: number
  ) => {
    try {
      const response = await fetch(`/api/user/${userId}/inventory-items`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          inventoryItemId: inventoryItemId,
          storeItemId: storeItemId,
        }),
      });

      if (!response.ok) {
        const error = await response.text();
        setNotification({ message: error, type: "Error" });
        return;
      }

      const data = await response.json();

      if (response.status == 200) {
        // Return success message
        setNotification({ message: "Item has been upgraded", type: "Success" });
        fetchInventoryItems();
        fetchBankAccount();
      }

      if (response.status == 400) {
        // return error message
        setNotification({ message: data.error, type: "Error" });
      }
    } catch (error) {
      if (error instanceof Error) {
        setNotification({ message: error.message, type: "Error" });
      } else {
        setNotification({ message: "An unknown error occured", type: "Error" });
      }
    }
  };

  const createStakingSource = async () => {
    try {
      const response = await fetch(`/api/user/${userId}/staking-sources`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
      });

      const data = await response.json();

      if (response.status == 200) {
        // Return success message
        setNotification({ message: "Moon has been minted", type: "Success" });
        fetchInventoryItems();
        fetchStakingSources();
        fetchBankAccount();
      }

      if (response.status == 400) {
        // return error message
        setNotification({ message: data.error, type: "Error" });
      }
    } catch (error) {
      if (error instanceof Error) {
        setNotification({ message: error.message, type: "Error" });
      } else {
        setNotification({ message: "An unknown error occured", type: "Error" });
      }
    }
  };

  const handleCloseNotification = () => {
    setNotification(null);
  };

  const handleMenuItemClick = (componentKey: string) => {
    setActiveComponent(componentKey);
  };

  if (!userId)
    return (
      <>
        <Navbar setUserId={setUserId} />
        <p>Please login</p>
      </>
    );

  if (isLoading) {
    return <p>Loading...</p>;
  }

  return (
    <>
      <Navbar setUserId={setUserId} />
      {notification && (
        <NotificationPopover
          notification={notification}
          onClose={handleCloseNotification}
        />
      )}
      <BankAccountsView
        bankAccount={bankAccount}
        sellResource={sellResource}
        gameConfig={gameConfig}
      />
      <div className="grid grid-cols-1 md:grid-cols-6 p-4 gap-8">
        <NavbarVertical
          onMenuItemClick={handleMenuItemClick}
          activeItem={activeComponent}
        />
        {activeComponent === "stakingsourcesview" && (
          <StakingSourcesView
            stakingSources={stakingSources}
            inventoryItems={inventoryItems}
            claimStake={claimStake}
            startStake={startStake}
            createStakingSource={createStakingSource}
          />
        )}
        {activeComponent === "inventoryitemview" && (
          <InventoryItemView
            stakes={userStakes}
            inventoryItems={inventoryItems}
            upgradeInventoryItem={upgradeInventoryItem}
          />
        )}
        {activeComponent === "storeitemview" && (
          <StoreItemView
            inventoryItems={inventoryItems}
            storeItems={storeItems}
            buyStoreItem={buyStoreItem}
          />
        )}
      </div>
    </>
  );
}
