"use client";

import { useFeedbackModal } from "@/app/components/providers/feedback-modal-provider";
import { useLoadingModal } from "@/app/components/providers/loading-modal-provider";
import type { Branch } from "@/lib/api/branches";
import type { DiningTableCategory } from "@/lib/api/dining-table-categories";
import {
  fetchDiningTableEditData,
  type DiningTable,
  type DiningTableEditData,
} from "@/lib/api/dining-tables";
import { getErrorMessage } from "@/lib/api/types";
import { useBranches } from "@/lib/query/hooks/branches";
import { useDiningTableCategories } from "@/lib/query/hooks/dining-table-categories";
import {
  useCreateDiningTables,
  useDeleteDiningTable,
  useDiningTables,
  useUpdateDiningTable,
  useUpdateDiningTableStatus,
  type DiningTableFormData,
  type DiningTableStatusTogglePayload,
} from "@/lib/query/hooks/dining-tables";
import { queryKeys } from "@/lib/query/query-keys";
import { useQueryClient } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { useClientPagination } from "@/lib/hooks/use-client-pagination";
import { IconButton } from "../ui/button";
import { DataPagination } from "../ui/data-pagination";
import { DataTableSection } from "../ui/data-table-section";
import { IconAdd } from "../ui/icons";
import { PageEnter, PageTextEnter } from "../ui/page-enter";
import { ALL_CATEGORIES, SemuaMejaFilters } from "./semua-meja-filters";
import {
  SemuaMejaFormModal,
  formatTableNumberForDisplay,
  normalizeTableNumberForApi,
} from "./semua-meja-form-modal";
import { SemuaMejaTable, type SemuaMejaTableRow } from "./semua-meja-table";

const EMPTY_ITEMS: DiningTable[] = [];
const EMPTY_CATEGORIES: DiningTableCategory[] = [];
const EMPTY_BRANCHES: Branch[] = [];

type FormModalState =
  | { mode: "create" }
  | { mode: "edit"; editData: DiningTableEditData };

function getCategoryName(
  item: DiningTable,
  categoryNameById: Map<number, string>,
) {
  if (item.tableCategoryName !== "-") {
    return item.tableCategoryName;
  }

  if (item.tableCategoryId == null) {
    return "-";
  }

  return categoryNameById.get(item.tableCategoryId) ?? "-";
}

export function SemuaMejaView() {
  const queryClient = useQueryClient();
  const { showLoading, hideLoading } = useLoadingModal();
  const { showDeleteConfirm, showSaveSuccess } = useFeedbackModal();
  const diningTablesQuery = useDiningTables();
  const categoriesQuery = useDiningTableCategories();
  const branchesQuery = useBranches();
  const createMutation = useCreateDiningTables();
  const updateMutation = useUpdateDiningTable();
  const deleteMutation = useDeleteDiningTable();
  const updateStatusMutation = useUpdateDiningTableStatus();

  const items = diningTablesQuery.data ?? EMPTY_ITEMS;
  const categories = categoriesQuery.data ?? EMPTY_CATEGORIES;
  const branches = branchesQuery.data ?? EMPTY_BRANCHES;

  const [search, setSearch] = useState("");
  const [category, setCategory] = useState(ALL_CATEGORIES);
  const [mutationError, setMutationError] = useState<string | null>(null);
  const [formModal, setFormModal] = useState<FormModalState | null>(null);
  const [isOpeningEditModal, setIsOpeningEditModal] = useState(false);

  const isSubmitting =
    createMutation.isPending ||
    updateMutation.isPending ||
    deleteMutation.isPending;

  const isInitialLoading =
    diningTablesQuery.isPending ||
    categoriesQuery.isPending ||
    branchesQuery.isPending;

  const error =
    mutationError ??
    (diningTablesQuery.error
      ? getErrorMessage(diningTablesQuery.error, "Gagal memuat data meja.")
      : categoriesQuery.error
        ? getErrorMessage(categoriesQuery.error, "Gagal memuat kategori meja.")
        : branchesQuery.error
          ? getErrorMessage(branchesQuery.error, "Gagal memuat data cabang.")
          : null);

  const categoryNameById = useMemo(() => {
    return new Map(categories.map((item) => [item.id, item.name]));
  }, [categories]);

  const categoryIdByName = useMemo(() => {
    return new Map(categories.map((item) => [item.name, item.id]));
  }, [categories]);

  const branchNameById = useMemo(() => {
    return new Map(branches.map((branch) => [branch.id, branch.name]));
  }, [branches]);

  const tableRows = useMemo<SemuaMejaTableRow[]>(() => {
    return items.map((item) => ({
      item,
      categoryName: getCategoryName(item, categoryNameById),
      branchName:
        item.branchId != null
          ? (branchNameById.get(item.branchId) ?? "-")
          : "-",
    }));
  }, [items, categoryNameById, branchNameById]);

  const filteredItems = useMemo(() => {
    const query = search.trim().toLowerCase();

    return tableRows.filter((row) => {
      const displayNumber = formatTableNumberForDisplay(
        row.item.tableNumber,
      ).toLowerCase();
      const normalizedNumber = normalizeTableNumberForApi(
        row.item.tableNumber,
      ).toLowerCase();

      const matchesSearch =
        query.length === 0 ||
        displayNumber.includes(query) ||
        normalizedNumber.includes(query) ||
        row.categoryName.toLowerCase().includes(query);

      const matchesCategory =
        category === ALL_CATEGORIES ||
        row.item.tableCategoryId === categoryIdByName.get(category);

      return matchesSearch && matchesCategory;
    });
  }, [tableRows, search, category, categoryIdByName]);

  const {
    setPage,
    paginatedItems,
    startIndex,
    clampPageAfterDelete,
    paginationProps,
  } = useClientPagination(filteredItems);

  function closeFormModal() {
    setFormModal(null);
    setMutationError(null);
  }

  async function runWithLoading<T>(
    message: string,
    action: () => Promise<T>,
  ): Promise<T> {
    showLoading({
      message,
      ariaLabel: "Memproses data meja",
    });

    try {
      return await action();
    } finally {
      hideLoading();
    }
  }

  async function handleCreate(data: DiningTableFormData) {
    setMutationError(null);

    try {
      await runWithLoading("Jangan tutup, proses sedang berlangsung", () =>
        createMutation.mutateAsync(data),
      );
      setFormModal(null);
      setPage(1);
      showSaveSuccess({
        description: "Data meja telah tersimpan dengan aman.",
        onPrimary: () => setFormModal({ mode: "create" }),
      });
    } catch (err) {
      setMutationError(getErrorMessage(err, "Gagal menyimpan meja."));
    }
  }

  async function handleEdit(id: number) {
    setMutationError(null);
    setIsOpeningEditModal(true);
    showLoading({
      message: "Jangan tutup, proses sedang berlangsung",
      ariaLabel: "Memuat data meja",
    });

    try {
      const editData = await queryClient.fetchQuery({
        queryKey: queryKeys.diningTables.detail(id),
        queryFn: () => fetchDiningTableEditData(id),
      });
      setFormModal({ mode: "edit", editData });
    } catch (err) {
      setMutationError(getErrorMessage(err, "Gagal memuat data meja."));
      setFormModal(null);
    } finally {
      hideLoading();
      setIsOpeningEditModal(false);
    }
  }

  async function handleUpdate(data: DiningTableFormData) {
    if (!formModal || formModal.mode !== "edit") return;

    setMutationError(null);

    try {
      await runWithLoading("Jangan tutup, proses sedang berlangsung", () =>
        updateMutation.mutateAsync({
          id: formModal.editData.id,
          data,
          currentStatus: formModal.editData.status,
          branchAssignments: formModal.editData.branchAssignments,
        }),
      );
      setFormModal(null);
      showSaveSuccess({
        description: "Data meja telah tersimpan dengan aman.",
        onPrimary: () => setFormModal({ mode: "create" }),
      });
    } catch (err) {
      setMutationError(getErrorMessage(err, "Gagal memperbarui meja."));
    }
  }

  async function handleDelete(row: SemuaMejaTableRow) {
    setMutationError(null);

    try {
      await runWithLoading("Jangan tutup, proses sedang berlangsung", () =>
        deleteMutation.mutateAsync(row.item.id),
      );
      clampPageAfterDelete(filteredItems.length - 1);
    } catch (err) {
      setMutationError(getErrorMessage(err, "Gagal menghapus meja."));
      throw err;
    }
  }

  function handleDeleteRequest(row: SemuaMejaTableRow) {
    showDeleteConfirm({
      onConfirm: () => handleDelete(row),
    });
  }

  function handleFormSubmit(data: DiningTableFormData) {
    if (formModal?.mode === "edit") {
      void handleUpdate(data);
      return;
    }

    void handleCreate(data);
  }

  function handleSearchChange(value: string) {
    setSearch(value);
    setPage(1);
  }

  function handleCategoryChange(value: string) {
    setCategory(value);
    setPage(1);
  }

  async function handleToggleVisible(payload: DiningTableStatusTogglePayload) {
    setMutationError(null);

    try {
      await updateStatusMutation.mutateAsync(payload);
    } catch (err) {
      setMutationError(
        getErrorMessage(err, "Gagal memperbarui tampilan meja."),
      );
    }
  }

  return (
    <PageEnter className="flex min-h-0 flex-1 flex-col">
      <div className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-[10px] border border-neutral-40 bg-neutral-10">
        <div className="relative flex shrink-0 items-center gap-2 px-5 pt-5">
          <div className="absolute top-5 left-0 h-5 w-1 rounded-r-sm bg-primary-500" />
          <PageTextEnter
            as="h1"
            delay={0.08}
            className="text-l-medium flex-1 text-neutral-100"
          >
            Semua Meja
          </PageTextEnter>
          <PageEnter delay={0.12}>
            <IconButton
              icon={<IconAdd />}
              onClick={() => setFormModal({ mode: "create" })}
              disabled={isOpeningEditModal}
            >
              Tambah Meja
            </IconButton>
          </PageEnter>
        </div>

        <div className="flex min-h-0 flex-1 flex-col gap-4 overflow-hidden p-5">
          {error && (
            <PageEnter delay={0.1}>
              <p className="text-m-regular rounded-lg border border-danger-200 bg-danger-50 px-4 py-3 text-danger-700">
                {error}
              </p>
            </PageEnter>
          )}

          <PageEnter delay={0.12}>
            <SemuaMejaFilters
              search={search}
              category={category}
              categories={categories}
              onSearchChange={handleSearchChange}
              onCategoryChange={handleCategoryChange}
            />
          </PageEnter>

          {isInitialLoading ? (
            <p className="text-m-regular text-neutral-80">Memuat data...</p>
          ) : filteredItems.length === 0 ? (
            <PageEnter delay={0.18}>
              <p className="text-m-regular rounded-lg border border-dashed border-neutral-40 bg-neutral-20 px-5 py-8 text-center text-neutral-80">
                Belum ada data meja.
              </p>
            </PageEnter>
          ) : (
            <PageEnter delay={0.2} className="flex min-h-0 flex-1 flex-col">
              <DataTableSection
                pagination={<DataPagination {...paginationProps} />}
              >
                <SemuaMejaTable
                  items={paginatedItems}
                  startIndex={startIndex}
                  onEdit={(id) => void handleEdit(id)}
                  onDelete={handleDeleteRequest}
                  onToggleVisible={(payload) =>
                    void handleToggleVisible(payload)
                  }
                />
              </DataTableSection>
            </PageEnter>
          )}
        </div>
      </div>

      <SemuaMejaFormModal
        key={
          formModal?.mode === "edit"
            ? `edit-${formModal.editData.id}`
            : "create"
        }
        open={formModal !== null}
        mode={formModal?.mode ?? "create"}
        branches={branches}
        categories={categories}
        initialEditData={
          formModal?.mode === "edit" ? formModal.editData : null
        }
        isSubmitting={isSubmitting}
        onClose={closeFormModal}
        onSubmit={handleFormSubmit}
      />
    </PageEnter>
  );
}
