import { useCallback, useMemo, useState } from "react";
import { GridRowSelectionModel } from "@mui/x-data-grid";

/** all = 搜索結果默認全選（排除列表 opt-out）；none = 全不選；include = 從全不選起逐項勾選；exclude = 從全選起逐項取消 */
export type DoSelectionMode = "all" | "none" | "include" | "exclude";

type RowWithId = { id: number };

export function useDoSearchRowSelection(
  searchAllDos: RowWithId[],
  setValue: (name: "ids", value: GridRowSelectionModel) => void,
) {
  const [selectionMode, setSelectionMode] = useState<DoSelectionMode>("all");
  const [excludedRowIds, setExcludedRowIds] = useState<number[]>([]);
  const [includedRowIds, setIncludedRowIds] = useState<number[]>([]);

  const resetSelection = useCallback(() => {
    setSelectionMode("all");
    setExcludedRowIds([]);
    setIncludedRowIds([]);
  }, []);

  const excludedIdSet = useMemo(() => new Set(excludedRowIds), [excludedRowIds]);
  const includedIdSet = useMemo(() => new Set(includedRowIds), [includedRowIds]);

  const rowSelectionModel = useMemo<GridRowSelectionModel>(() => {
    const pageIds = searchAllDos.map((r) => r.id);
    if (selectionMode === "none") {
      return [];
    }
    if (selectionMode === "include") {
      return pageIds.filter((id) => includedIdSet.has(id));
    }
    return pageIds.filter((id) => !excludedIdSet.has(id));
  }, [selectionMode, searchAllDos, excludedIdSet, includedIdSet]);

  const applyRowSelectionChange = useCallback(
    (newModel: GridRowSelectionModel) => {
      const pageIds = searchAllDos.map((r) => r.id);
      const selectedSet = new Set(
        newModel.map((id) => (typeof id === "string" ? Number(id) : id)),
      );

      const allPageWasSelected =
        selectionMode !== "none" &&
        selectionMode !== "include" &&
        pageIds.length > 0 &&
        pageIds.every((id) => !excludedIdSet.has(id));

      const allPageWasSelectedInIncludeMode =
        selectionMode === "include" &&
        pageIds.length > 0 &&
        pageIds.every((id) => includedIdSet.has(id));

      const allPageNowSelected =
        pageIds.length > 0 && pageIds.every((id) => selectedSet.has(id));

      if (
        newModel.length === 0 &&
        (allPageWasSelected || allPageWasSelectedInIncludeMode)
      ) {
        setSelectionMode("none");
        setExcludedRowIds([]);
        setIncludedRowIds([]);
        setValue("ids", []);
        return;
      }

      if (allPageNowSelected) {
        setSelectionMode("all");
        setExcludedRowIds([]);
        setIncludedRowIds([]);
        setValue("ids", newModel);
        return;
      }

      if (selectionMode === "all" || selectionMode === "exclude") {
        setSelectionMode("exclude");
        setExcludedRowIds((prev) => {
          const next = new Set(prev);
          for (const id of pageIds) {
            next.delete(id);
          }
          for (const id of pageIds) {
            if (!selectedSet.has(id)) {
              next.add(id);
            }
          }
          return Array.from(next);
        });
      } else {
        setSelectionMode("include");
        setIncludedRowIds((prev) => {
          const next = new Set(prev);
          for (const id of pageIds) {
            next.delete(id);
          }
          for (const id of pageIds) {
            if (selectedSet.has(id)) {
              next.add(id);
            }
          }
          return Array.from(next);
        });
      }
      setValue("ids", newModel);
    },
    [
      searchAllDos,
      setValue,
      selectionMode,
      excludedIdSet,
      includedIdSet,
    ],
  );

  const resolveIdsForBatchRelease = useCallback(
    (allMatchingIds: number[]) => {
      if (selectionMode === "none") {
        return [];
      }
      if (selectionMode === "include") {
        return allMatchingIds.filter((id) => includedIdSet.has(id));
      }
      return allMatchingIds.filter((id) => !excludedIdSet.has(id));
    },
    [selectionMode, excludedIdSet, includedIdSet],
  );

  return {
    selectionMode,
    excludedRowIds,
    excludedIdSet,
    rowSelectionModel,
    applyRowSelectionChange,
    resetSelection,
    resolveIdsForBatchRelease,
  };
}
