"use client";

import { gql } from "@apollo/client";
import { useMutation, useQuery } from "@apollo/client/react";
import {
  ReactNode,
  createContext,
  useContext,
  useEffect,
  useState,
} from "react";

import { eateryClient } from "./apollo-clients";
import {
  EateryEntity,
  type MenuItemEntity,
  type addMenuItemMutation,
  type allEateriesQuery,
  deleteMenuItemMutation,
  updateMenuItemMutation,
} from "./types";

// ─── Types ────────────────────────────────────────────────────────────────────

export type ManagerTab = "products" | "reviews";

interface ManagerContextType {
  // Data
  products: MenuItemEntity[];
  eateryId: string | null;
  eatery?: EateryEntity;

  // Active tab
  activeTab: ManagerTab;
  setActiveTab: (tab: ManagerTab) => void;

  // MenuItemEntity actions
  addProduct: (product: MenuItemEntity) => void;
  updateProduct: (product: MenuItemEntity) => void;
  deleteProduct: (id: string) => void;
  toggleProductAvailability: (product: MenuItemEntity) => void;
}

// ─── Context ──────────────────────────────────────────────────────────────────

const ManagerContext = createContext<ManagerContextType | undefined>(undefined);

// ___ Graphql __________________________________________________________________

const GET_EATERY_MENU = gql`
  query GetEateryMenu {
    allEateries {
      id
      name
      menuItems {
        id
        name
        imageUrl
        available
        description
        price
      }
    }
  }
`;

const ADD_MENU_ITEM = gql`
  mutation addMenuItem($menuItem: AddMenuItemInput!) {
    addMenuItem(menuItem: $menuItem) {
      id
      name
      imageUrl
      available
      description
      price
    }
  }
`;

const UPDATE_MENU_ITEM = gql`
  mutation updateMenuItem($menuItem: UpdateMenuItemInput!) {
    updateMenuItem(menuItem: $menuItem) {
      id
      name
      imageUrl
      available
      description
      price
    }
  }
`;

const DELETE_MENU_ITEM = gql`
  mutation deleteMenuItem($input: String!) {
    deleteMenuItem(menuItemId: $input)
  }
`;

// ─── Provider ─────────────────────────────────────────────────────────────────

export function ManagerProvider({ children }: { children: ReactNode }) {
  const [products, setProducts] = useState<MenuItemEntity[]>([]);
  const [eatery, setEatery] = useState<EateryEntity>();
  const [activeTab, setActiveTab] = useState<ManagerTab>("products");

  const { data } = useQuery<allEateriesQuery>(GET_EATERY_MENU, {
    client: eateryClient,
    fetchPolicy: "network-only",
  });

  const eateryId = data?.allEateries?.[0]?.id ?? null;

  const [mutateAddMenuItem] = useMutation<addMenuItemMutation>(ADD_MENU_ITEM, {
    client: eateryClient,
  });

  const [mutateUpdateMenuItem] = useMutation<updateMenuItemMutation>(
    UPDATE_MENU_ITEM,
    { client: eateryClient },
  );

  const [mutateDeleteMenuItem] = useMutation<deleteMenuItemMutation>(
    DELETE_MENU_ITEM,
    { client: eateryClient },
  );

  useEffect(() => {
    if (data?.allEateries?.[0]) {
      setProducts(data.allEateries[0].menuItems);
      setEatery(data.allEateries[0]);
    }
  }, [data]);

  // ── MenuItemEntity actions ──────────────────────────────────────────────────────

  const addProduct = async (product: MenuItemEntity) => {
    const { data } = await mutateAddMenuItem({
      variables: {
        menuItem: product,
      },
    });

    if (!data) return;

    // addMenuItem backend does not persist imageUrl (constructor only maps name+price).
    // If the caller provided an imageUrl, patch it immediately via updateMenuItem
    // which uses MapStruct and correctly saves all fields.
    if (product.imageUrl && data.addMenuItem?.id) {
      const { data: updated } = await mutateUpdateMenuItem({
        variables: {
          menuItem: { id: data.addMenuItem.id, imageUrl: product.imageUrl },
        },
      });
      if (updated) {
        setProducts((prev) => [...prev, updated.updateMenuItem]);
        return;
      }
    }

    setProducts((prev) => [...prev, data.addMenuItem]);
  };

  const updateProduct = async (product: MenuItemEntity) => {
    const { data } = await mutateUpdateMenuItem({
      variables: {
        menuItem: product,
      },
    });

    if (data)
      setProducts((prev) =>
        prev.map((p) => (p.id === product.id ? data.updateMenuItem : p)),
      );
  };

  const deleteProduct = async (id: string) => {
    const { data } = await mutateDeleteMenuItem({ variables: { input: id } });

    if (data)
      setProducts((prev) =>
        prev.filter((p) => !(p.id == id && data.deleteMenuItem)),
      );
  };

  const toggleProductAvailability = async (product: MenuItemEntity) => {
    const { data } = await mutateUpdateMenuItem({
      variables: {
        menuItem: { ...product, available: !product.available },
      },
    });

    if (data)
      setProducts((prev) =>
        prev.map((p) => (p.id === product.id ? data.updateMenuItem : p)),
      );
  };

  return (
    <ManagerContext.Provider
      value={{
        eatery,
        products,
        eateryId,
        activeTab,
        setActiveTab,
        addProduct,
        updateProduct,
        deleteProduct,
        toggleProductAvailability,
      }}
    >
      {children}
    </ManagerContext.Provider>
  );
}

// ─── Hook ─────────────────────────────────────────────────────────────────────

export function useManager() {
  const context = useContext(ManagerContext);
  if (context === undefined) {
    throw new Error("useManager must be used within a ManagerProvider");
  }
  return context;
}
