/*
 * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { useOsdkMetadata } from "@osdk/react";
import { isEqual } from "lodash-es";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { assertUnreachable } from "../../shared/assertUnreachable.js";
import { buildWhereClause, getActiveLinkedFilters } from "../utils/filterStateToWhereClause.js";
import { filterHasActiveState } from "../utils/filterValues.js";
import { getFilterKey } from "../utils/getFilterKey.js";
import { narrowObjectSet } from "../utils/narrowObjectSet.js";
import { useStableMapEntries } from "./useStableMapEntries.js";
function buildInitialStates(definitions) {
  const states = new Map();
  if (!definitions) {
    return states;
  }
  for (const definition of definitions) {
    const key = getFilterKey(definition);
    switch (definition.type) {
      case "PROPERTY":
        {
          const state = definition.filterState;
          if (state) {
            states.set(key, state);
          }
          break;
        }
      case "HAS_LINK":
      case "KEYWORD_SEARCH":
      case "CUSTOM":
        {
          const state = definition.defaultFilterState;
          if (state) {
            states.set(key, state);
          }
          break;
        }
      case "STATIC_VALUES":
        {
          const state = definition.filterState;
          if (state) {
            states.set(key, state);
          }
          break;
        }
      case "LINKED_PROPERTY":
        {
          const innerState = definition.defaultLinkedFilterState;
          if (innerState) {
            states.set(key, {
              type: "linkedProperty",
              linkedFilterState: innerState
            });
          }
          break;
        }
      default:
        assertUnreachable(definition);
    }
  }
  return states;
}
export function useFilterListState(props) {
  const {
    objectType,
    objectSet,
    filterDefinitions,
    onFilterStateChanged,
    onFilterClauseChanged,
    onEffectiveObjectSet,
    initialFilterStates
  } = props;
  const {
    metadata
  } = useOsdkMetadata(objectType);
  const onFilterClauseChangedRef = useRef(onFilterClauseChanged);
  onFilterClauseChangedRef.current = onFilterClauseChanged;
  const onEffectiveObjectSetRef = useRef(onEffectiveObjectSet);
  onEffectiveObjectSetRef.current = onEffectiveObjectSet;
  const filterDefinitionsRef = useRef(filterDefinitions);
  filterDefinitionsRef.current = filterDefinitions;
  const propertyTypes = useMemo(() => {
    const map = new Map();
    if (metadata?.properties) {
      for (const [key, prop] of Object.entries(metadata.properties)) {
        if (typeof prop.type === "string") {
          map.set(key, {
            type: prop.type,
            multiplicity: prop.multiplicity === true
          });
        }
      }
    }
    return map;
  }, [metadata?.properties]);

  // Captured once on first render to provide a stable baseline for the reset
  // button's enabled state. `useState`'s lazy initializer pins the value for
  // the lifetime of the component (unlike `useMemo`, which React may discard).
  const [initialFilterStatesSnapshot] = useState(() => {
    const snapshot = buildInitialStates(filterDefinitions);
    if (initialFilterStates) {
      for (const [key, state] of initialFilterStates) {
        snapshot.set(key, state);
      }
    }
    return snapshot;
  });
  const [filterStates, setFilterStates] = useState(() => new Map(initialFilterStatesSnapshot));
  const setFilterState = useCallback((filterKey, state) => {
    setFilterStates(prev => {
      const next = new Map(prev);
      next.set(filterKey, state);
      return next;
    });
    const definition = filterDefinitionsRef.current?.find(d => getFilterKey(d) === filterKey);
    if (definition) {
      onFilterStateChanged?.(definition, state);
    }
  }, [onFilterStateChanged]);
  const clearFilterState = useCallback(filterKey => {
    setFilterStates(prev => {
      const next = new Map(prev);
      next.delete(filterKey);
      return next;
    });
  }, []);
  const reset = useCallback(() => {
    setFilterStates(new Map(initialFilterStatesSnapshot));
  }, [initialFilterStatesSnapshot]);
  const whereClause = useMemo(() => buildWhereClause(filterDefinitions, filterStates, propertyTypes), [filterDefinitions, filterStates, propertyTypes]);
  const linkedFilters = useMemo(() => getActiveLinkedFilters(filterDefinitions, filterStates), [filterDefinitions, filterStates]);
  const effectiveObjectSet = useMemo(() => objectSet == null ? undefined : narrowObjectSet(objectSet, whereClause, linkedFilters), [objectSet, whereClause, linkedFilters]);
  useEffect(() => {
    onFilterClauseChangedRef.current?.(whereClause);
  }, [whereClause]);
  useEffect(() => {
    if (effectiveObjectSet == null) {
      return;
    }
    onEffectiveObjectSetRef.current?.(effectiveObjectSet);
  }, [effectiveObjectSet]);
  const perFilterWhereClauses = useStableMapEntries(useMemo(() => {
    const map = new Map();
    for (const definition of filterDefinitions ?? []) {
      const key = getFilterKey(definition);
      map.set(key, buildWhereClause(filterDefinitions, filterStates, propertyTypes, key));
    }
    return map;
  }, [filterDefinitions, filterStates, propertyTypes]));
  const perFilterLinkedFilters = useStableMapEntries(useMemo(() => {
    const map = new Map();
    for (const definition of filterDefinitions ?? []) {
      const key = getFilterKey(definition);
      map.set(key, getActiveLinkedFilters(filterDefinitions, filterStates, key));
    }
    return map;
  }, [filterDefinitions, filterStates]));
  const activeFilterCount = useMemo(() => {
    let count = 0;
    for (const state of filterStates.values()) {
      if (filterHasActiveState(state)) {
        count++;
      }
    }
    return count;
  }, [filterStates]);
  const hasChangesFromInitial = useMemo(() => !isEqual(filterStates, initialFilterStatesSnapshot), [filterStates, initialFilterStatesSnapshot]);
  return useMemo(() => ({
    filterStates,
    setFilterState,
    clearFilterState,
    whereClause,
    linkedFilters,
    perFilterWhereClauses,
    perFilterLinkedFilters,
    activeFilterCount,
    hasChangesFromInitial,
    reset
  }), [filterStates, setFilterState, clearFilterState, whereClause, linkedFilters, perFilterWhereClauses, perFilterLinkedFilters, activeFilterCount, hasChangesFromInitial, reset]);
}
//# sourceMappingURL=useFilterListState.js.map