import { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useTranslation } from "react-i18next";
import {
  createIngredientCatalogItem,
  deleteIngredientCatalogItem,
  fetchIngredientCatalogItems,
  fetchIngredientCategories,
  updateIngredientCatalogItem,
} from "@/api/ingredient-catalog.api";
import { extractApiError } from "@/api/axiosInstance";
import { ErrorState } from "@/components/ui/ErrorState";
import { EmptyState } from "@/components/ui/EmptyState";
import { SortableTh } from "@/components/ui/SortableTh";
import type { UpsertIngredientNutritionItemInput, IngredientNutritionItem } from "@/types/ingredient-catalog.types";
import { ingredientDisplayName } from "@/utils/ingredient-catalog.util";
import { nextSort, sortBy, type SortDirection } from "@/utils/sort.util";

type IngredientSortColumn = "name" | "category" | "calories" | "protein" | "fat" | "carbs" | "fiber";

const EMPTY_FORM: UpsertIngredientNutritionItemInput = {
  categoryId: 0,
  name: "",
  namePl: "",
  caloriesPer100G: 0,
  proteinGPer100G: 0,
  fatGPer100G: 0,
  carbsGPer100G: 0,
  fiberGPer100G: null,
  sortOrder: 0,
  isActive: true,
};

export function IngredientCatalogPage() {
  const { t, i18n } = useTranslation();
  const queryClient = useQueryClient();
  const [category, setCategory] = useState<string>("");
  const [search, setSearch] = useState("");
  const [debouncedSearch, setDebouncedSearch] = useState("");
  const [showForm, setShowForm] = useState(false);
  const [editingId, setEditingId] = useState<number | null>(null);
  const [form, setForm] = useState<UpsertIngredientNutritionItemInput>({ ...EMPTY_FORM });
  const [formError, setFormError] = useState<string | null>(null);
  const [sort, setSort] = useState<{ column: IngredientSortColumn; direction: SortDirection }>({
    column: "name",
    direction: "asc",
  });

  const categoriesQuery = useQuery({
    queryKey: ["ingredient-categories"],
    queryFn: fetchIngredientCategories,
  });

  const itemsQuery = useQuery({
    queryKey: ["ingredient-catalog", category, debouncedSearch],
    queryFn: () =>
      fetchIngredientCatalogItems({
        category: category || undefined,
        search: debouncedSearch || undefined,
      }),
  });

  const saveMutation = useMutation({
    mutationFn: async () => {
      const payload = {
        ...form,
        name: form.name.trim(),
        namePl: form.namePl?.trim() || null,
        fiberGPer100G: form.fiberGPer100G ?? null,
      };
      if (editingId) {
        return updateIngredientCatalogItem(editingId, payload);
      }
      return createIngredientCatalogItem(payload);
    },
    onSuccess: () => {
      setShowForm(false);
      setEditingId(null);
      setFormError(null);
      void queryClient.invalidateQueries({ queryKey: ["ingredient-categories"] });
      void queryClient.invalidateQueries({ queryKey: ["ingredient-catalog"] });
    },
    onError: (err) => {
      setFormError(extractApiError(err, t("errors.saveIngredientFailed")));
    },
  });

  const deleteMutation = useMutation({
    mutationFn: deleteIngredientCatalogItem,
    onSuccess: () => {
      void queryClient.invalidateQueries({ queryKey: ["ingredient-categories"] });
      void queryClient.invalidateQueries({ queryKey: ["ingredient-catalog"] });
    },
  });

  const categoryLabel = (code: string, fallback: string) =>
    t(`ingredientCatalog.categories.${code}`, { defaultValue: fallback });

  const totalCount = useMemo(
    () => categoriesQuery.data?.reduce((n, c) => n + c.itemCount, 0) ?? 0,
    [categoriesQuery.data],
  );

  const onSearchChange = (value: string) => {
    setSearch(value);
    window.clearTimeout((window as unknown as { __ingSearch?: number }).__ingSearch);
    (window as unknown as { __ingSearch?: number }).__ingSearch = window.setTimeout(
      () => setDebouncedSearch(value.trim()),
      300,
    );
  };

  const openCreateForm = () => {
    setEditingId(null);
    setForm({ ...EMPTY_FORM, categoryId: categoriesQuery.data?.[0]?.id ?? 0 });
    setFormError(null);
    setShowForm(true);
  };

  const openEditForm = (item: IngredientNutritionItem) => {
    setEditingId(item.id);
    setForm({
      categoryId: item.categoryId,
      name: item.name,
      namePl: item.namePl ?? "",
      caloriesPer100G: item.caloriesPer100G,
      proteinGPer100G: item.proteinGPer100G,
      fatGPer100G: item.fatGPer100G,
      carbsGPer100G: item.carbsGPer100G,
      fiberGPer100G: item.fiberGPer100G,
      sortOrder: 0,
      isActive: true,
    });
    setFormError(null);
    setShowForm(true);
  };

  const closeForm = () => {
    setShowForm(false);
    setEditingId(null);
    setFormError(null);
  };

  const saveForm = () => {
    if (!form.categoryId || !form.name.trim()) {
      setFormError(t("ingredientCatalog.formInvalid"));
      return;
    }
    saveMutation.mutate();
  };

  const deleteItem = (id: number) => {
    if (!window.confirm(t("ingredientCatalog.deleteConfirm"))) return;
    deleteMutation.mutate(id);
  };

  const loading = categoriesQuery.isLoading || itemsQuery.isLoading;
  const error = categoriesQuery.error ?? itemsQuery.error;
  const items = itemsQuery.data ?? [];

  const sortedItems = useMemo(() => {
    const { column, direction } = sort;
    return sortBy(items, direction, (item) => {
      switch (column) {
        case "name":
          return ingredientDisplayName(item, i18n.language);
        case "category":
          return item.categoryCode;
        case "calories":
          return item.caloriesPer100G;
        case "protein":
          return Number(item.proteinGPer100G);
        case "fat":
          return Number(item.fatGPer100G);
        case "carbs":
          return Number(item.carbsGPer100G);
        case "fiber":
          return item.fiberGPer100G != null ? Number(item.fiberGPer100G) : null;
      }
    });
  }, [items, sort, i18n.language]);

  const toggleSort = (column: IngredientSortColumn) => {
    setSort((current) => nextSort(current, column));
  };

  return (
    <div className="space-y-6">
      <header className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <h1 className="text-2xl font-extrabold tracking-tight sm:text-3xl">
            {t("ingredientCatalog.title")}
          </h1>
          <p className="mt-1 text-slate-500 dark:text-slate-400">{t("ingredientCatalog.subtitle")}</p>
        </div>
        <button type="button" className="btn-secondary" onClick={openCreateForm}>
          + {t("ingredientCatalog.addIngredient")}
        </button>
      </header>

      {showForm ? (
        <section className="card space-y-4 p-5">
          <h2 className="text-lg font-bold">
            {editingId ? t("ingredientCatalog.editIngredient") : t("ingredientCatalog.addIngredient")}
          </h2>
          {formError ? <p className="text-sm text-red-600">{formError}</p> : null}
          <div className="grid gap-4 sm:grid-cols-2">
            <label className="block text-sm sm:col-span-2">
              <span className="font-medium">{t("ingredientCatalog.columns.category")}</span>
              <select
                className="select mt-1 w-full"
                value={form.categoryId}
                onChange={(e) => setForm((prev) => ({ ...prev, categoryId: Number(e.target.value) }))}
              >
                <option value={0} disabled>
                  {t("ingredientCatalog.selectCategory")}
                </option>
                {(categoriesQuery.data ?? []).map((cat) => (
                  <option key={cat.id} value={cat.id}>
                    {categoryLabel(cat.code, cat.name)}
                  </option>
                ))}
              </select>
            </label>
            <label className="block text-sm">
              <span className="font-medium">{t("ingredientCatalog.nameEn")}</span>
              <input
                className="input mt-1 w-full"
                value={form.name}
                onChange={(e) => setForm((prev) => ({ ...prev, name: e.target.value }))}
              />
            </label>
            <label className="block text-sm">
              <span className="font-medium">{t("ingredientCatalog.namePlLabel")}</span>
              <input
                className="input mt-1 w-full"
                value={form.namePl ?? ""}
                onChange={(e) => setForm((prev) => ({ ...prev, namePl: e.target.value }))}
              />
            </label>
            {(
              [
                ["caloriesPer100G", "ingredientCatalog.columns.calories", 1],
                ["proteinGPer100G", "ingredientCatalog.columns.protein", 0.1],
                ["fatGPer100G", "ingredientCatalog.columns.fat", 0.1],
                ["carbsGPer100G", "ingredientCatalog.columns.carbs", 0.1],
                ["fiberGPer100G", "ingredientCatalog.columns.fiber", 0.1],
              ] as const
            ).map(([key, labelKey, step]) => (
              <label key={key} className="block text-sm">
                <span className="font-medium">{t(labelKey)}</span>
                <input
                  type="number"
                  min={0}
                  step={step}
                  className="input mt-1 w-full"
                  value={form[key] ?? ""}
                  onChange={(e) =>
                    setForm((prev) => ({
                      ...prev,
                      [key]: e.target.value === "" ? null : Number(e.target.value),
                    }))
                  }
                />
              </label>
            ))}
          </div>
          <div className="flex gap-2">
            <button
              type="button"
              className="btn-primary"
              disabled={saveMutation.isPending}
              onClick={saveForm}
            >
              {t("common.save")}
            </button>
            <button type="button" className="btn-secondary" onClick={closeForm}>
              {t("common.cancel")}
            </button>
          </div>
        </section>
      ) : null}

      <div className="flex flex-wrap gap-2">
        <button
          type="button"
          onClick={() => setCategory("")}
          className={`rounded-xl px-4 py-2 text-sm font-semibold transition ${
            category === ""
              ? "bg-brand-600 text-white"
              : "bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-300"
          }`}
        >
          {t("ingredientCatalog.allCategories")} ({totalCount})
        </button>
        {(categoriesQuery.data ?? []).map((cat) => (
          <button
            key={cat.code}
            type="button"
            onClick={() => setCategory(cat.code)}
            className={`rounded-xl px-4 py-2 text-sm font-semibold transition ${
              category === cat.code
                ? "bg-brand-600 text-white"
                : "bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-300"
            }`}
          >
            {categoryLabel(cat.code, cat.name)} ({cat.itemCount})
          </button>
        ))}
      </div>

      <label className="block max-w-md text-sm">
        <span className="font-medium">{t("common.search")}</span>
        <input
          className="input mt-1 w-full"
          value={search}
          onChange={(e) => onSearchChange(e.target.value)}
          placeholder={t("ingredientCatalog.searchPlaceholder")}
        />
      </label>

      {loading && (
        <div className="card p-8 text-center text-slate-500">{t("common.loading")}</div>
      )}

      {error && (
        <ErrorState
          message={extractApiError(error, t("errors.loadIngredientCatalogFailed"))}
          onRetry={() => {
            categoriesQuery.refetch();
            itemsQuery.refetch();
          }}
        />
      )}

      {!loading && !error && items.length === 0 && (
        <EmptyState
          title={t("ingredientCatalog.noResultsTitle")}
          description={t("ingredientCatalog.noResultsDescription")}
        />
      )}

      {!loading && !error && items.length > 0 && (
        <div className="card overflow-hidden">
          <div className="overflow-x-auto">
            <table className="min-w-full text-left text-sm">
              <thead className="border-b border-slate-200 bg-slate-50 text-xs uppercase tracking-wide text-slate-500 dark:border-slate-700 dark:bg-slate-800/50">
                <tr>
                  <SortableTh column="name" label={t("ingredientCatalog.columns.name")} sort={sort} onSort={(c) => toggleSort(c as IngredientSortColumn)} />
                  <SortableTh column="category" label={t("ingredientCatalog.columns.category")} sort={sort} onSort={(c) => toggleSort(c as IngredientSortColumn)} />
                  <SortableTh column="calories" label={t("ingredientCatalog.columns.calories")} sort={sort} onSort={(c) => toggleSort(c as IngredientSortColumn)} />
                  <SortableTh column="protein" label={t("ingredientCatalog.columns.protein")} sort={sort} onSort={(c) => toggleSort(c as IngredientSortColumn)} />
                  <SortableTh column="fat" label={t("ingredientCatalog.columns.fat")} sort={sort} onSort={(c) => toggleSort(c as IngredientSortColumn)} />
                  <SortableTh column="carbs" label={t("ingredientCatalog.columns.carbs")} sort={sort} onSort={(c) => toggleSort(c as IngredientSortColumn)} />
                  <SortableTh column="fiber" label={t("ingredientCatalog.columns.fiber")} sort={sort} onSort={(c) => toggleSort(c as IngredientSortColumn)} />
                  <th className="px-4 py-3" />
                </tr>
              </thead>
              <tbody className="divide-y divide-slate-100 dark:divide-slate-800">
                {sortedItems.map((item) => (
                  <tr key={item.id} className="hover:bg-slate-50 dark:hover:bg-slate-800/30">
                    <td className="px-4 py-3 font-medium">
                      {ingredientDisplayName(item, i18n.language)}
                    </td>
                    <td className="px-4 py-3 text-slate-500">
                      {categoryLabel(item.categoryCode, item.categoryName)}
                    </td>
                    <td className="px-4 py-3">{item.caloriesPer100G}</td>
                    <td className="px-4 py-3">{Number(item.proteinGPer100G).toFixed(1)}</td>
                    <td className="px-4 py-3">{Number(item.fatGPer100G).toFixed(1)}</td>
                    <td className="px-4 py-3">{Number(item.carbsGPer100G).toFixed(1)}</td>
                    <td className="px-4 py-3">
                      {item.fiberGPer100G != null ? Number(item.fiberGPer100G).toFixed(1) : "—"}
                    </td>
                    <td className="px-4 py-3 text-right whitespace-nowrap">
                      <button
                        type="button"
                        className="mr-2 text-brand-600"
                        onClick={() => openEditForm(item)}
                      >
                        {t("common.edit")}
                      </button>
                      <button
                        type="button"
                        className="text-red-500"
                        onClick={() => deleteItem(item.id)}
                      >
                        {t("common.delete")}
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <p className="border-t border-slate-200 px-4 py-3 text-xs text-slate-400 dark:border-slate-700">
            {t("ingredientCatalog.per100gNote")}
          </p>
        </div>
      )}
    </div>
  );
}
