/*
 * 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 { useOsdkAggregation } from "@osdk/react";
import classnames from "classnames";
import React, { memo, useCallback, useMemo } from "react";
import { assertUnreachable } from "../../shared/assertUnreachable.js";
import { FilterInputExcludeRow } from "../base/FilterInputExcludeRow.js";
import { ContainsTextInput } from "../base/inputs/ContainsTextInput.js";
import { DateRangeHistogramInput } from "../base/inputs/DateRangeHistogramInput.js";
import { ListogramInput } from "../base/inputs/ListogramInput.js";
import { MultiDateInput } from "../base/inputs/MultiDateInput.js";
import { MultiSelectInput } from "../base/inputs/MultiSelectInput.js";
import { NullValueWrapper } from "../base/inputs/NullValueWrapper.js";
import { NumberRangeInput } from "../base/inputs/NumberRangeInput.js";
import { SingleDateInput } from "../base/inputs/SingleDateInput.js";
import { SingleSelectInput } from "../base/inputs/SingleSelectInput.js";
import { TextTagsInput } from "../base/inputs/TextTagsInput.js";
import { TimelineInput } from "../base/inputs/TimelineInput.js";
import { ToggleInput } from "../base/inputs/ToggleInput.js";
import { useDualScopeAggregation } from "../hooks/useDualScopeAggregation.js";
import { usePropertyAggregation } from "../hooks/usePropertyAggregation.js";
import { EMPTY_LINKED_FILTERS } from "../types/LinkedFilterTypes.js";
import { createGroupByAggregateOptions, createNullCountAggregateOptions, createNullWhereClause } from "../utils/aggregationHelpers.js";
import { coerceToString, coerceToStringArray } from "../utils/coerceFilterValue.js";
import { clearFilterState } from "../utils/filterValues.js";
import { narrowObjectSet } from "../utils/narrowObjectSet.js";
import styles from "../base/inputs/LinkedPropertyInput.module.css.js";
function LinkedPropertyInputInner({
  objectSet,
  whereClause,
  linkedFilters = EMPTY_LINKED_FILTERS,
  definition,
  filterState,
  onFilterStateChanged,
  showFilteredOutValues,
  searchQuery,
  excludeRowOpen,
  className,
  style,
  layout
}) {
  const scoped = useMemo(() => narrowObjectSet(objectSet, whereClause, linkedFilters), [objectSet, whereClause, linkedFilters]);
  const linkedObjectSet = useMemo(() => scoped.pivotTo(definition.linkName), [scoped, definition.linkName]);
  // Filtered-out rows on a linked facet compare against the raw source so
  // direct filters surface as count=0 entries on the linked side.
  const emptySourceLinkedObjectSet = useMemo(() => showFilteredOutValues ? objectSet.pivotTo(definition.linkName) : undefined, [showFilteredOutValues, objectSet, definition.linkName]);
  const linkedObjectType = linkedObjectSet.$objectSetInternals.def;
  const linkedPropertyKey = definition.linkedPropertyKey;
  const innerState = filterState?.type === "linkedProperty" ? filterState.linkedFilterState : undefined;
  const isExcluding = innerState?.isExcluding ?? false;
  const includeNull = innerState?.includeNull;
  const wrappedOnChange = useCallback(innerFilterState => {
    onFilterStateChanged({
      type: "linkedProperty",
      linkedFilterState: innerFilterState
    });
  }, [onFilterStateChanged]);
  const handleClearAll = useCallback(() => {
    const cleared = clearFilterState(filterState);
    if (cleared != null) {
      onFilterStateChanged(cleared);
    }
  }, [filterState, onFilterStateChanged]);
  const onSelectChange = useCallback(selectedValues => {
    wrappedOnChange({
      type: "SELECT",
      selectedValues,
      isExcluding
    });
  }, [wrappedOnChange, isExcluding]);
  const onSingleSelectChange = useCallback(selectedValue => {
    wrappedOnChange({
      type: "SELECT",
      selectedValues: selectedValue !== undefined ? [selectedValue] : [],
      isExcluding
    });
  }, [wrappedOnChange, isExcluding]);
  const onContainsTextChange = useCallback(value => {
    wrappedOnChange({
      type: "CONTAINS_TEXT",
      value
    });
  }, [wrappedOnChange]);
  const onToggleChange = useCallback(enabled => {
    wrappedOnChange({
      type: "TOGGLE",
      enabled
    });
  }, [wrappedOnChange]);
  const onNumberRangeChange = useCallback((minValue, maxValue) => {
    wrappedOnChange({
      type: "NUMBER_RANGE",
      minValue,
      maxValue,
      includeNull
    });
  }, [wrappedOnChange, includeNull]);
  const onDateRangeChange = useCallback((minValue, maxValue) => {
    wrappedOnChange({
      type: "DATE_RANGE",
      minValue,
      maxValue,
      includeNull
    });
  }, [wrappedOnChange, includeNull]);
  const onExactMatchChange = useCallback(values => {
    wrappedOnChange({
      type: "EXACT_MATCH",
      values,
      isExcluding
    });
  }, [wrappedOnChange, isExcluding]);
  const onDateSelectChange = useCallback(date => {
    wrappedOnChange({
      type: "SELECT",
      selectedValues: date !== undefined ? [date] : [],
      isExcluding
    });
  }, [wrappedOnChange, isExcluding]);
  const onMultiDateChange = useCallback(dates => {
    wrappedOnChange({
      type: "SELECT",
      selectedValues: dates
    });
  }, [wrappedOnChange]);
  const onTimelineChange = useCallback((start, end) => {
    wrappedOnChange({
      type: "TIMELINE",
      startDate: start,
      endDate: end,
      isExcluding
    });
  }, [wrappedOnChange, isExcluding]);
  const onNullChange = useCallback(newIncludeNull => {
    if (innerState?.type === "NUMBER_RANGE") {
      wrappedOnChange({
        ...innerState,
        includeNull: newIncludeNull
      });
    } else if (innerState?.type === "DATE_RANGE") {
      wrappedOnChange({
        ...innerState,
        includeNull: newIncludeNull
      });
    } else {
      wrappedOnChange({
        type: "NUMBER_RANGE",
        minValue: undefined,
        maxValue: undefined,
        includeNull: newIncludeNull
      });
    }
  }, [wrappedOnChange, innerState]);
  const content = (() => {
    switch (definition.linkedFilterComponent) {
      case "MULTI_SELECT":
        {
          const values = innerState?.type === "SELECT" ? coerceToStringArray(innerState.selectedValues) : [];
          return /*#__PURE__*/React.createElement(LinkedMultiSelectInput, {
            objectType: linkedObjectType,
            objectSet: linkedObjectSet,
            emptySourceObjectSet: emptySourceLinkedObjectSet,
            propertyKey: linkedPropertyKey,
            selectedValues: values,
            onChange: onSelectChange,
            showCount: definition.showCount,
            renderValue: definition.renderValue,
            layout: layout
          });
        }
      case "SINGLE_SELECT":
        {
          const value = innerState?.type === "SELECT" ? coerceToString(innerState.selectedValues[0]) : undefined;
          return /*#__PURE__*/React.createElement(LinkedSingleSelectInput, {
            objectType: linkedObjectType,
            objectSet: linkedObjectSet,
            emptySourceObjectSet: emptySourceLinkedObjectSet,
            propertyKey: linkedPropertyKey,
            selectedValue: value,
            onChange: onSingleSelectChange,
            showCount: definition.showCount,
            renderValue: definition.renderValue
          });
        }
      case "CONTAINS_TEXT":
        {
          const value = innerState?.type === "CONTAINS_TEXT" ? innerState.value : undefined;
          return /*#__PURE__*/React.createElement(ContainsTextInput, {
            value: value,
            onChange: onContainsTextChange,
            placeholder: `Search ${String(definition.linkedPropertyKey)}...`
          });
        }
      case "TOGGLE":
        {
          const enabled = innerState?.type === "TOGGLE" ? innerState.enabled : false;
          return /*#__PURE__*/React.createElement(ToggleInput, {
            enabled: enabled,
            onChange: onToggleChange
          });
        }
      case "NUMBER_RANGE":
        {
          const nr = innerState?.type === "NUMBER_RANGE" ? innerState : undefined;
          return /*#__PURE__*/React.createElement(LinkedNumberRangeInput, {
            objectType: linkedObjectType,
            objectSet: linkedObjectSet,
            propertyKey: linkedPropertyKey,
            minValue: nr?.minValue,
            maxValue: nr?.maxValue,
            includeNull: nr?.includeNull,
            onChange: onNumberRangeChange,
            onNullChange: onNullChange
          });
        }
      case "DATE_RANGE":
        {
          const dr = innerState?.type === "DATE_RANGE" ? innerState : undefined;
          return /*#__PURE__*/React.createElement(LinkedDateRangeInput, {
            objectType: linkedObjectType,
            objectSet: linkedObjectSet,
            propertyKey: linkedPropertyKey,
            minValue: dr?.minValue,
            maxValue: dr?.maxValue,
            includeNull: dr?.includeNull,
            onChange: onDateRangeChange,
            onNullChange: onNullChange
          });
        }
      case "LISTOGRAM":
        {
          const exactState = innerState?.type === "EXACT_MATCH" ? innerState : undefined;
          const selectedValues = exactState ? coerceToStringArray(exactState.values) : [];
          return /*#__PURE__*/React.createElement(LinkedListogramInput, {
            objectType: linkedObjectType,
            objectSet: linkedObjectSet,
            emptySourceObjectSet: emptySourceLinkedObjectSet,
            propertyKey: linkedPropertyKey,
            selectedValues: selectedValues,
            onChange: onExactMatchChange,
            searchQuery: searchQuery,
            showCount: definition.showCount,
            renderValue: definition.renderValue
          });
        }
      case "TEXT_TAGS":
        {
          const exactState = innerState?.type === "EXACT_MATCH" ? innerState : undefined;
          const tags = exactState ? coerceToStringArray(exactState.values) : [];
          return /*#__PURE__*/React.createElement(LinkedTextTagsInput, {
            objectType: linkedObjectType,
            objectSet: linkedObjectSet,
            propertyKey: linkedPropertyKey,
            tags: tags,
            onChange: onExactMatchChange
          });
        }
      case "SINGLE_DATE":
        {
          const selectedDate = innerState?.type === "SELECT" ? innerState.selectedValues[0] instanceof Date ? innerState.selectedValues[0] : undefined : undefined;
          return /*#__PURE__*/React.createElement(SingleDateInput, {
            selectedDate: selectedDate,
            onChange: onDateSelectChange,
            showClearButton: true
          });
        }
      case "MULTI_DATE":
        {
          const selectedDates = innerState?.type === "SELECT" ? innerState.selectedValues.filter(v => v instanceof Date) : [];
          return /*#__PURE__*/React.createElement(MultiDateInput, {
            selectedDates: selectedDates,
            onChange: onMultiDateChange,
            showClearAll: true
          });
        }
      case "TIMELINE":
        {
          const tl = innerState?.type === "TIMELINE" ? innerState : undefined;
          return /*#__PURE__*/React.createElement(TimelineInput, {
            startDate: tl?.startDate,
            endDate: tl?.endDate,
            onChange: onTimelineChange
          });
        }
      default:
        return assertUnreachable(definition.linkedFilterComponent);
    }
  })();
  return /*#__PURE__*/React.createElement(FilterInputExcludeRow, {
    excludeRowOpen: excludeRowOpen,
    filterState: filterState,
    onFilterStateChanged: onFilterStateChanged,
    onClearAll: handleClearAll
  }, /*#__PURE__*/React.createElement("div", {
    className: classnames(styles.linkedProperty, className),
    style: style
  }, content));
}
export const LinkedPropertyInput = /*#__PURE__*/memo(LinkedPropertyInputInner);
function LinkedMultiSelectInput({
  objectType,
  objectSet,
  emptySourceObjectSet,
  propertyKey,
  selectedValues,
  onChange,
  showCount,
  renderValue,
  layout
}) {
  const {
    data,
    isLoading,
    error
  } = useDualScopeAggregation(objectType, propertyKey, objectSet, emptySourceObjectSet, {
    selectedValues
  });
  return /*#__PURE__*/React.createElement(MultiSelectInput, {
    values: data,
    isLoading: isLoading,
    error: error,
    selectedValues: selectedValues,
    onChange: onChange,
    showCounts: showCount,
    renderValue: renderValue,
    layout: layout
  });
}
function LinkedSingleSelectInput({
  objectType,
  objectSet,
  emptySourceObjectSet,
  propertyKey,
  selectedValue,
  onChange,
  showCount,
  renderValue
}) {
  const selectedValues = useMemo(() => selectedValue != null ? [selectedValue] : [], [selectedValue]);
  const {
    data,
    isLoading,
    error
  } = useDualScopeAggregation(objectType, propertyKey, objectSet, emptySourceObjectSet, {
    selectedValues
  });
  return /*#__PURE__*/React.createElement(SingleSelectInput, {
    values: data,
    isLoading: isLoading,
    error: error,
    selectedValue: selectedValue,
    onChange: onChange,
    showCounts: showCount,
    renderValue: renderValue,
    ariaLabel: `Select ${propertyKey}`
  });
}
function LinkedListogramInput({
  objectType,
  objectSet,
  emptySourceObjectSet,
  propertyKey,
  selectedValues,
  onChange,
  searchQuery,
  showCount,
  renderValue
}) {
  const {
    data,
    maxCount,
    isLoading,
    error
  } = useDualScopeAggregation(objectType, propertyKey, objectSet, emptySourceObjectSet, {
    selectedValues
  });
  return /*#__PURE__*/React.createElement(ListogramInput, {
    values: data,
    maxCount: maxCount,
    isLoading: isLoading,
    error: error,
    selectedValues: selectedValues,
    onChange: onChange,
    searchQuery: searchQuery,
    showCount: showCount,
    renderValue: renderValue
  });
}
const TEXT_TAGS_OPTIONS = {
  limit: 50
};
function LinkedTextTagsInput({
  objectType,
  objectSet,
  propertyKey,
  tags,
  onChange
}) {
  const {
    data,
    isLoading,
    error
  } = usePropertyAggregation(objectType, propertyKey, objectSet, TEXT_TAGS_OPTIONS);
  return /*#__PURE__*/React.createElement(TextTagsInput, {
    suggestions: data,
    isLoading: isLoading,
    error: error,
    tags: tags,
    onChange: onChange,
    suggestionLimit: 10
  });
}
function useLinkedRangeData(objectType, propertyKey, objectSet) {
  const aggregateOptions = useMemo(() => createGroupByAggregateOptions(propertyKey), [propertyKey]);
  const histogramArgs = useMemo(() => ({
    aggregate: aggregateOptions,
    objectSet
  }), [aggregateOptions, objectSet]);
  const {
    data: aggregateData,
    isLoading: histLoading
  } = useOsdkAggregation(objectType, histogramArgs);
  const nullCountAggregateOptions = useMemo(() => createNullCountAggregateOptions(), []);
  const nullWhereClause = useMemo(() => createNullWhereClause(propertyKey), [propertyKey]);
  const nullCountArgs = useMemo(() => ({
    where: nullWhereClause,
    aggregate: nullCountAggregateOptions,
    objectSet
  }), [nullWhereClause, nullCountAggregateOptions, objectSet]);
  const {
    data: nullCountData,
    isLoading: nullLoading
  } = useOsdkAggregation(objectType, nullCountArgs);
  const nullCount = useMemo(() => {
    if (!nullCountData) return 0;
    const result = nullCountData;
    if ("$count" in result && typeof result.$count === "number") {
      return result.$count;
    }
    return 0;
  }, [nullCountData]);
  return {
    aggregateData,
    histLoading,
    nullCount,
    nullLoading
  };
}
function LinkedNumberRangeInput({
  objectType,
  objectSet,
  propertyKey,
  minValue,
  maxValue,
  includeNull,
  onChange,
  onNullChange
}) {
  const {
    aggregateData,
    histLoading,
    nullCount,
    nullLoading
  } = useLinkedRangeData(objectType, propertyKey, objectSet);
  const valueCountPairs = useMemo(() => {
    if (!aggregateData) return [];
    const pairs = [];
    for (const item of aggregateData) {
      const rawValue = item.$group[propertyKey];
      if (rawValue != null) {
        const parsed = parseFloat(String(rawValue));
        if (!isNaN(parsed)) {
          pairs.push({
            value: parsed,
            count: item.$count ?? 0
          });
        }
      }
    }
    return pairs;
  }, [aggregateData, propertyKey]);
  return /*#__PURE__*/React.createElement(NullValueWrapper, {
    nullCount: nullCount,
    isLoading: nullLoading,
    includeNull: includeNull,
    onIncludeNullChange: onNullChange
  }, /*#__PURE__*/React.createElement(NumberRangeInput, {
    valueCountPairs: valueCountPairs,
    isLoading: histLoading,
    minValue: minValue,
    maxValue: maxValue,
    onChange: onChange
  }));
}
function LinkedDateRangeInput({
  objectType,
  objectSet,
  propertyKey,
  minValue,
  maxValue,
  includeNull,
  onChange,
  onNullChange
}) {
  const {
    aggregateData,
    histLoading,
    nullCount,
    nullLoading
  } = useLinkedRangeData(objectType, propertyKey, objectSet);
  const valueCountPairs = useMemo(() => {
    if (!aggregateData) return [];
    const pairs = [];
    for (const item of aggregateData) {
      const rawValue = item.$group[propertyKey];
      if (rawValue != null) {
        const date = new Date(String(rawValue));
        if (!isNaN(date.getTime())) {
          pairs.push({
            value: date,
            count: item.$count ?? 0
          });
        }
      }
    }
    return pairs;
  }, [aggregateData, propertyKey]);
  return /*#__PURE__*/React.createElement(NullValueWrapper, {
    nullCount: nullCount,
    isLoading: nullLoading,
    includeNull: includeNull,
    onIncludeNullChange: onNullChange
  }, /*#__PURE__*/React.createElement(DateRangeHistogramInput, {
    valueCountPairs: valueCountPairs,
    isLoading: histLoading,
    minValue: minValue,
    maxValue: maxValue,
    onChange: onChange
  }));
}
//# sourceMappingURL=LinkedPropertyInput.js.map