import { ref } from "vue";
import { useAsyncKey } from "../use-utils";
import { usePublicExploreApi } from "~/composables/api/api-client";
import { useUserApi } from "~/composables/api";
import type { OrderByNullPosition, Recipe } from "~/lib/api/types/recipe";
import type { RecipeSearchQuery } from "~/lib/api/user/recipes/recipe";

export const allRecipes = ref<Recipe[]>([]);
export const recentRecipes = ref<Recipe[]>([]);

function getParams(
  orderBy: string | null = null,
  orderDirection = "desc",
  orderByNullPosition: OrderByNullPosition | null = null,
  query: RecipeSearchQuery | null = null,
  queryFilter: string | null = null,
) {
  return {
    orderBy,
    orderDirection,
    orderByNullPosition,
    paginationSeed: query?._searchSeed, // propagate searchSeed to stabilize random order pagination
    searchSeed: query?._searchSeed, // unused, but pass it along for completeness of data
    search: query?.search,
    cookbook: query?.cookbook,
    households: query?.households,
    categories: query?.categories,
    requireAllCategories: query?.requireAllCategories,
    tags: query?.tags,
    requireAllTags: query?.requireAllTags,
    tools: query?.tools,
    requireAllTools: query?.requireAllTools,
    foods: query?.foods,
    requireAllFoods: query?.requireAllFoods,
    queryFilter,
  };
};

export const useLazyRecipes = function (publicGroupSlug: string | null = null) {
  const router = useRouter();

  // passing the group slug switches to using the public API
  const api = publicGroupSlug ? usePublicExploreApi(publicGroupSlug).explore : useUserApi();

  const recipes = ref<Recipe[]>([]);

  async function fetchMore(
    page: number,
    perPage: number,
    orderBy: string | null = null,
    orderDirection = "desc",
    orderByNullPosition: OrderByNullPosition | null = null,
    query: RecipeSearchQuery | null = null,
    queryFilter: string | null = null,
  ) {
    const { data, error } = await api.recipes.getAll(
      page,
      perPage,
      getParams(orderBy, orderDirection, orderByNullPosition, query, queryFilter),
    );

    if (error?.response?.status === 404) {
      router.push("/login");
    }

    return data ? data.items : [];
  }

  function appendRecipes(val: Array<Recipe>) {
    val.forEach((recipe) => {
      recipes.value.push(recipe);
    });
  }

  function assignSorted(val: Array<Recipe>) {
    recipes.value = val;
  }

  function removeRecipe(slug: string) {
    for (let i = 0; i < recipes?.value?.length; i++) {
      if (recipes?.value[i].slug === slug) {
        recipes?.value.splice(i, 1);
        break;
      }
    }
  }

  function replaceRecipes(val: Array<Recipe>) {
    recipes.value = val;
  }

  async function getRandom(query: RecipeSearchQuery | null = null, queryFilter: string | null = null) {
    query = query || {};
    query._searchSeed = query._searchSeed || Date.now().toString();
    const { data } = await api.recipes.getAll(1, 1, getParams("random", "desc", null, query, queryFilter));
    if (data?.items.length) {
      return data.items[0];
    }
  }

  return {
    recipes,
    fetchMore,
    appendRecipes,
    assignSorted,
    removeRecipe,
    replaceRecipes,
    getRandom,
  };
};

export const useRecipes = (
  all = false,
  fetchRecipes = true,
  loadFood = false,
  queryFilter: string | null = null,
  publicGroupSlug: string | null = null,
) => {
  const api = publicGroupSlug ? usePublicExploreApi(publicGroupSlug).explore : useUserApi();

  // recipes is non-reactive!!
  const { recipes, page, perPage } = (() => {
    if (all) {
      return {
        recipes: allRecipes,
        page: 1,
        perPage: -1,
      };
    }
    else {
      return {
        recipes: recentRecipes,
        page: 1,
        perPage: 30,
      };
    }
  })();

  async function refreshRecipes() {
    const { data } = await api.recipes.getAll(page, perPage, { loadFood, orderBy: "created_at", queryFilter });
    if (data) {
      recipes.value = data.items;
    }
  }

  function getAllRecipes() {
    useAsyncData(useAsyncKey(), async () => {
      await refreshRecipes();
    });
  }

  function assignSorted(val: Array<Recipe>) {
    recipes.value = val;
  }

  if (fetchRecipes) {
    getAllRecipes();
  }

  return { getAllRecipes, assignSorted, refreshRecipes };
};
