declare module "@univerjs/core/facade" {
  import type { IFSheetsFilterEnumMixin, IFSheetsFilterEventNameMixin, ISheetsRangeFilterClearedEventParams, ISheetsRangeFilteredEventParams } from "@univerjs/sheets-filter/facade";

  interface ISheetsFilterEventParamConfig {
      SheetBeforeRangeFilter: ISheetsRangeFilteredEventParams;
      SheetRangeFiltered: ISheetsRangeFilteredEventParams;
      SheetBeforeRangeFilterClear: ISheetsRangeFilterClearedEventParams;
      SheetRangeFilterCleared: ISheetsRangeFilterClearedEventParams;
  }
}

declare module "@univerjs/sheets-filter" {
  import type { BooleanNumber, Nullable } from "@univerjs/core";

  // @ts-ignore: optional external type dependency may be absent in generated workspaces.
  import type { ISheetCommandSharedParams } from "@univerjs/sheets";

  /**
   * Parameters of command {@link SetSheetsFilterCriteriaCommand}.
   * @property {number} col - the column index of the filter criteria
   * @property {Nullable<IFilterColumn>} criteria - the filter criteria to be set
   */
  interface ISetSheetsFilterCriteriaCommandParams extends ISheetCommandSharedParams {
      col: number;
      criteria: Nullable<IFilterColumn>;
  }

  /**
   * The filter criteria of a column.
   *
   * @property {number} colId The column number.
   * @property {IFilters} [filters] The basic filters (filter by value).
   * @property {ICustomFilters} [customFilters] The custom filters.
   */
  interface IFilterColumn {
      colId: number;
      filters?: IFilters;
      colorFilters?: IColorFilters;
      customFilters?: ICustomFilters;
  }

  /**
   * Basic filters (filter by value).
   *
   * @property {true} [blank] Filter by blank. If this field is present, blank cells would be visible.
   * @property {Array<string>} [filters] Filter by values. Cells with values in this array would be visible.
   */
  interface IFilters {
      blank?: true;
      filters?: Array<string>;
  }

  /**
   * Color filters.
   *
   * @property {Array<string | null>} [cellFillColor] The cell fill colors to filter by. If this field is present, cells with these fill colors would be visible.
   * @property {Array<string>} [cellTextColor] The cell text colors to filter by. If this field is present, cells with these text colors would be visible.
   */
  interface IColorFilters {
      cellFillColors?: Array<string | null>;
      cellTextColors?: Array<string>;
  }

  /**
   * Custom filters.
   *
   * @property {BooleanNumber.TRUE} and The logical operator of the custom filters. If this field is present,
   * the custom filters would be connected by 'and'. Otherwise, they would be connected by 'or'.
   * @property {ICustomFilter[]} customFilters The custom filters.
   */
  interface ICustomFilters {
      and?: BooleanNumber.TRUE;
      customFilters: [
          ICustomFilter
      ] | [
          ICustomFilter,
          ICustomFilter
      ];
  }

  /**
   * A custom filter.
   *
   * @property {string | number} val The value to be compared.
   * @property {CustomFilterOperator} [operator] The operator of the comparison. If this field is empty, the operator would be 'equal'.
   */
  interface ICustomFilter {
      val: string | number;
      operator?: CustomFilterOperator;
  }
}

declare module "@univerjs/sheets-filter/facade" {
  import { CustomFilterOperator } from "@univerjs/sheets-filter";

  import type { Nullable } from "@univerjs/core";

  import type { IEventBase } from "@univerjs/core/facade";

  import type { IFilterColumn, ISetSheetsFilterCriteriaCommandParams } from "@univerjs/sheets-filter";

  import type { FRange, FWorkbook, FWorksheet } from "@univerjs/sheets/facade";

  interface IFSheetsFilterEnumMixin {
      /** Please refer to {@link CustomFilterOperator}. */
      CustomFilterOperator: typeof CustomFilterOperator;
  }

  class FSheetsFilterEnumMixin {
      get CustomFilterOperator(): typeof CustomFilterOperator;
  }

  /**
   * The params of SheetRangeFiltered and SheetBeforeRangeFilter events.
   * @param workbook - The corresponding workbook wrapped in {@link FWorkbook}.
   * @param worksheet - The corresponding worksheet wrapped in {@link FWorksheet}.
   * @param col - The column on which the filter criteria is changed.
   * @param criteria - Raw filter criteria.
   */
  interface ISheetsRangeFilteredEventParams extends IEventBase, Pick<ISetSheetsFilterCriteriaCommandParams, 'criteria' | 'col'> {
      workbook: FWorkbook;
      worksheet: FWorksheet;
  }

  /**
   * The params of SheetRangeFilterCleared and SheetBeforeRangeFilterClear events.
   * @param workbook - The corresponding workbook wrapped in {@link FWorkbook}.
   * @param worksheet - The corresponding worksheet wrapped in {@link FWorksheet}.
   */
  interface ISheetsRangeFilterClearedEventParams extends IEventBase {
      workbook: FWorkbook;
      worksheet: FWorksheet;
  }

  interface IFSheetsFilterEventNameMixin {
      /**
       * This event will be emitted when the filter criteria on a column is changed.
       * @see {@link ISheetRangeFilteredParams}
       * @example
       * ```typescript
       * const callbackDisposable = univerAPI.addEvent(univerAPI.Event.SheetRangeFiltered, (params) => {
       *   console.log(params);
       *   const { workbook, worksheet, col, criteria } = params;
       *
       *   // your custom logic
       * });
       *
       * // Remove the event listener, use `callbackDisposable.dispose()`
       * ```
       */
      readonly SheetRangeFiltered: 'SheetRangeFiltered';
      /**
       * This event will be emitted before the filter criteria on a column is changed.
       * @see {@link ISheetRangeFilteredParams}
       * @example
       * ```typescript
       * const callbackDisposable = univerAPI.addEvent(univerAPI.Event.SheetBeforeRangeFilter, (params) => {
       *   console.log(params);
       *   const { workbook, worksheet, col, criteria } = params;
       *
       *   // your custom logic
       *
       *   // Cancel the filter criteria change operation
       *   params.cancel = true;
       * });
       *
       * // Remove the event listener, use `callbackDisposable.dispose()`
       * ```
       */
      readonly SheetBeforeRangeFilter: 'SheetBeforeRangeFilter';
      /**
       * This event will be emitted when the filter on a worksheet is cleared.
       * @see {@link ISheetRangeFilterClearedEventParams}
       * @example
       * ```typescript
       * const callbackDisposable = univerAPI.addEvent(univerAPI.Event.SheetRangeFilterCleared, (params) => {
       *   console.log(params);
       *   const { workbook, worksheet } = params;
       *
       *   // your custom logic
       * });
       *
       * // Remove the event listener, use `callbackDisposable.dispose()`
       * ```
       */
      readonly SheetRangeFilterCleared: 'SheetRangeFilterCleared';
      /**
       * This event will be emitted after the filter on a worksheet is cleared.
       * @see {@link ISheetRangeFilterClearedEventParams}
       * @example
       * ```typescript
       * const callbackDisposable = univerAPI.addEvent(univerAPI.Event.SheetBeforeRangeFilterClear, (params) => {
       *   console.log(params);
       *   const { workbook, worksheet } = params;
       *
       *   // your custom logic
       *
       *   // Cancel the filter clear operation
       *   params.cancel = true;
       * });
       *
       * // Remove the event listener, use `callbackDisposable.dispose()`
       * ```
       */
      readonly SheetBeforeRangeFilterClear: 'SheetBeforeRangeFilterClear';
  }

  class FSheetsFilterEventNameMixin {
      get SheetBeforeRangeFilter(): 'SheetBeforeRangeFilter';
      get SheetRangeFiltered(): 'SheetRangeFiltered';
      get SheetRangeFilterCleared(): 'SheetRangeFilterCleared';
      get SheetBeforeRangeFilterClear(): 'SheetBeforeRangeFilterClear';
  }

  /**
   * This interface class provides methods to modify the filter settings of a worksheet.
   * @hideconstructor
   */
  class FFilter {
      /**
       * Get the filtered out rows by this filter.
       * @returns {number[]} Filtered out rows by this filter.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       *
       * // Set some values of the range C1:F10
       * const fRange = fWorksheet.getRange('C1:F10');
       * fRange.setValues([
       *   [1, 2, 3, 4],
       *   [2, 3, 4, 5],
       *   [3, 4, 5, 6],
       *   [4, 5, 6, 7],
       *   [5, 6, 7, 8],
       *   [6, 7, 8, 9],
       *   [7, 8, 9, 10],
       *   [8, 9, 10, 11],
       *   [9, 10, 11, 12],
       *   [10, 11, 12, 13],
       * ]);
       *
       * // Create a filter on the range C1:F10
       * let fFilter = fRange.createFilter();
       *
       * // If the filter already exists, remove it and create a new one
       * if (!fFilter) {
       *   fRange.getFilter().remove();
       *   fFilter = fRange.createFilter();
       * }
       *
       * // Set the filter criteria of the column C, filter out the rows that are not 1, 5, 9
       * const column = fWorksheet.getRange('C:C').getColumn();
       * fFilter.setColumnFilterCriteria(column, {
       *   colId: 0,
       *   filters: {
       *     filters: ['1', '5', '9'],
       *   },
       * });
       *
       * // Get the filtered out rows
       * console.log(fFilter.getFilteredOutRows()); // [1, 2, 3, 5, 6, 7, 9]
       * ```
       */
      getFilteredOutRows(): number[];
      /**
       * Get the filter criteria of a column.
       * @param {number} column - The column index.
       * @returns {Nullable<IFilterColumn>} The filter criteria of the column.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       *
       * // Set some values of the range C1:F10
       * const fRange = fWorksheet.getRange('C1:F10');
       * fRange.setValues([
       *   [1, 2, 3, 4],
       *   [2, 3, 4, 5],
       *   [3, 4, 5, 6],
       *   [4, 5, 6, 7],
       *   [5, 6, 7, 8],
       *   [6, 7, 8, 9],
       *   [7, 8, 9, 10],
       *   [8, 9, 10, 11],
       *   [9, 10, 11, 12],
       *   [10, 11, 12, 13],
       * ]);
       *
       * // Create a filter on the range C1:F10
       * let fFilter = fRange.createFilter();
       *
       * // If the filter already exists, remove it and create a new one
       * if (!fFilter) {
       *   fRange.getFilter().remove();
       *   fFilter = fRange.createFilter();
       * }
       *
       * // Set the filter criteria of the column C, filter out the rows that are not 1, 5, 9
       * const column = fWorksheet.getRange('C:C').getColumn();
       * fFilter.setColumnFilterCriteria(column, {
       *   colId: 0,
       *   filters: {
       *     filters: ['1', '5', '9'],
       *   },
       * });
       *
       * // Print the filter criteria of the column C and D
       * console.log(fFilter.getColumnFilterCriteria(column)); // { colId: 0, filters: { filters: ['1', '5', '9'] } }
       * console.log(fFilter.getColumnFilterCriteria(column + 1)); // undefined
       * ```
       */
      getColumnFilterCriteria(column: number): Nullable<IFilterColumn>;
      /**
       * Clear the filter criteria of a column.
       * @param {number} column - The column index.
       * @returns {FFilter} The FFilter instance for chaining.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       *
       * // Set some values of the range C1:F10
       * const fRange = fWorksheet.getRange('C1:F10');
       * fRange.setValues([
       *   [1, 2, 3, 4],
       *   [2, 3, 4, 5],
       *   [3, 4, 5, 6],
       *   [4, 5, 6, 7],
       *   [5, 6, 7, 8],
       *   [6, 7, 8, 9],
       *   [7, 8, 9, 10],
       *   [8, 9, 10, 11],
       *   [9, 10, 11, 12],
       *   [10, 11, 12, 13],
       * ]);
       *
       * // Create a filter on the range C1:F10
       * let fFilter = fRange.createFilter();
       *
       * // If the filter already exists, remove it and create a new one
       * if (!fFilter) {
       *   fRange.getFilter().remove();
       *   fFilter = fRange.createFilter();
       * }
       *
       * // Set the filter criteria of the column C, filter out the rows that are not 1, 5, 9
       * const column = fWorksheet.getRange('C:C').getColumn();
       * fFilter.setColumnFilterCriteria(column, {
       *   colId: 0,
       *   filters: {
       *     filters: ['1', '5', '9'],
       *   },
       * });
       *
       * // Clear the filter criteria of the column C after 3 seconds
       * setTimeout(() => {
       *   fFilter.removeColumnFilterCriteria(column);
       * }, 3000);
       * ```
       */
      removeColumnFilterCriteria(column: number): FFilter;
      /**
       * Set the filter criteria of a column.
       * @param {number} column - The column index.
       * @param {ISetSheetsFilterCriteriaCommandParams['criteria']} criteria - The new filter criteria.
       * @returns {FFilter} The FFilter instance for chaining.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       *
       * // Set some values of the range C1:F10
       * const fRange = fWorksheet.getRange('C1:F10');
       * fRange.setValues([
       *   [1, 2, 3, 4],
       *   [2, 3, 4, 5],
       *   [3, 4, 5, 6],
       *   [4, 5, 6, 7],
       *   [5, 6, 7, 8],
       *   [6, 7, 8, 9],
       *   [7, 8, 9, 10],
       *   [8, 9, 10, 11],
       *   [9, 10, 11, 12],
       *   [10, 11, 12, 13],
       * ]);
       *
       * // Create a filter on the range C1:F10
       * let fFilter = fRange.createFilter();
       *
       * // If the filter already exists, remove it and create a new one
       * if (!fFilter) {
       *   fRange.getFilter().remove();
       *   fFilter = fRange.createFilter();
       * }
       *
       * // Set the filter criteria of the column C, filter out the rows that are not 1, 5, 9
       * const column = fWorksheet.getRange('C:C').getColumn();
       * fFilter.setColumnFilterCriteria(column, {
       *   colId: 0,
       *   filters: {
       *     filters: ['1', '5', '9'],
       *   },
       * });
       * ```
       */
      setColumnFilterCriteria(column: number, criteria: ISetSheetsFilterCriteriaCommandParams['criteria']): FFilter;
      /**
       * Get the range of the filter.
       * @returns {FRange} The range of the filter.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       * const fFilter = fWorksheet.getFilter();
       * console.log(fFilter?.getRange().getA1Notation());
       * ```
       */
      getRange(): FRange;
      /**
       * Remove the filter criteria of all columns.
       * @returns {FFilter} The FFilter instance for chaining.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       *
       * // Set some values of the range C1:F10
       * const fRange = fWorksheet.getRange('C1:F10');
       * fRange.setValues([
       *   [1, 2, 3, 4],
       *   [2, 3, 4, 5],
       *   [3, 4, 5, 6],
       *   [4, 5, 6, 7],
       *   [5, 6, 7, 8],
       *   [6, 7, 8, 9],
       *   [7, 8, 9, 10],
       *   [8, 9, 10, 11],
       *   [9, 10, 11, 12],
       *   [10, 11, 12, 13],
       * ]);
       *
       * // Create a filter on the range C1:F10
       * let fFilter = fRange.createFilter();
       *
       * // If the filter already exists, remove it and create a new one
       * if (!fFilter) {
       *   fRange.getFilter().remove();
       *   fFilter = fRange.createFilter();
       * }
       *
       * // Set the filter criteria of the column C, filter out the rows that are not 1, 5, 9
       * const column = fWorksheet.getRange('C:C').getColumn();
       * fFilter.setColumnFilterCriteria(column, {
       *   colId: 0,
       *   filters: {
       *     filters: ['1', '5', '9'],
       *   },
       * });
       *
       * // Clear the filter criteria of all columns after 3 seconds
       * setTimeout(() => {
       *   fFilter.removeFilterCriteria();
       * }, 3000);
       * ```
       */
      removeFilterCriteria(): FFilter;
      /**
       * Remove the filter from the worksheet.
       * @returns {boolean} True if the filter is removed successfully; otherwise, false.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       * const fRange = fWorksheet.getRange('A1:D14');
       * let fFilter = fRange.createFilter();
       *
       * // If the worksheet already has a filter, remove it and create a new filter.
       * if (!fFilter) {
       *   fWorksheet.getFilter().remove();
       *   fFilter = fRange.createFilter();
       * }
       * console.log(fFilter);
       * ```
       */
      remove(): boolean;
  }

  interface IFRangeSheetsFilterMixin {
      /**
       * Create a filter for the current range. If the worksheet already has a filter, this method would return `null`.
       * @returns {FFilter | null} The FFilter instance to handle the filter.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       * const fRange = fWorksheet.getRange('A1:D14');
       * let fFilter = fRange.createFilter();
       *
       * // If the worksheet already has a filter, remove it and create a new filter.
       * if (!fFilter) {
       *   fWorksheet.getFilter().remove();
       *   fFilter = fRange.createFilter();
       * }
       * console.log(fFilter, fFilter.getRange().getA1Notation());
       * ```
       */
      createFilter(this: FRange): FFilter | null;
      /**
       * Get the filter in the worksheet to which the range belongs. If the worksheet does not have a filter, this method would return `null`.
       * Normally, you can directly call `getFilter` on {@link FWorksheet}.
       * @returns {FFilter | null} The FFilter instance to handle the filter.
       * @example
       * ```typescript
       * const fWorkbook = univerAPI.getActiveWorkbook();
       * const fWorksheet = fWorkbook.getSheetByName('Sheet1');
       * if (!fWorksheet) return;
       * const fRange = fWorksheet.getRange('A1:D14');
       * let fFilter = fRange.getFilter();
       *
       * // If the worksheet does not have a filter, create a new filter.
       * if (!fFilter) {
       *    fFilter = fRange.createFilter();
       * }
       * console.log(fFilter, fFilter.getRange().getA1Notation());
       * ```
       */
      getFilter(): FFilter | null;
  }

  class FRangeSheetsFilterMixin {
      createFilter(): FFilter | null;
      /**
       * Get the filter for the current range's worksheet.
       * @returns {FFilter | null} The interface class to handle the filter. If the worksheet does not have a filter,
       * this method would return `null`.
       */
      getFilter(): FFilter | null;
  }

  class FUniverSheetsFilterMixin {
  }

  interface IFWorksheetFilterMixin {
      /**
       * Get the filter for the current worksheet.
       * @returns {FFilter | null} The interface class to handle the filter. If the worksheet does not have a filter,
       * this method would return `null`.
       * @example
       * ```typescript
       * const workbook = univerAPI.getActiveWorkbook();
       * const worksheet = workbook.getSheetByName('Sheet1');
       * if (!worksheet) return;
       * const filter = worksheet.getFilter();
       * console.log(filter, filter?.getRange().getA1Notation());
       * ```
       */
      getFilter(): FFilter | null;
  }

  class FWorksheetFilterMixin {
      getFilter(): FFilter | null;
  }
}

declare module "@univerjs/core/facade" {
  import type { IFSheetsFilterEnumMixin, IFSheetsFilterEventNameMixin, ISheetsRangeFilterClearedEventParams, ISheetsRangeFilteredEventParams } from "@univerjs/sheets-filter/facade";

  interface FEnum extends IFSheetsFilterEnumMixin {
  }
}

declare module "@univerjs/core/facade" {
  import type { IFSheetsFilterEnumMixin, IFSheetsFilterEventNameMixin, ISheetsRangeFilterClearedEventParams, ISheetsRangeFilteredEventParams } from "@univerjs/sheets-filter/facade";

  interface FEventName extends IFSheetsFilterEventNameMixin {
  }

  interface IEventParamConfig extends ISheetsFilterEventParamConfig {
  }
}

declare module "@univerjs/sheets/facade" {
  import type { IFRangeSheetsFilterMixin, IFWorksheetFilterMixin } from "@univerjs/sheets-filter/facade";

  interface FRange extends IFRangeSheetsFilterMixin {
  }
}

declare module "@univerjs/sheets/facade" {
  import type { IFRangeSheetsFilterMixin, IFWorksheetFilterMixin } from "@univerjs/sheets-filter/facade";

  interface FWorksheet extends IFWorksheetFilterMixin {
  }
}

declare module "@univerjs/sheets-filter" {
  enum CustomFilterOperator {
    EQUAL = "equal",
    GREATER_THAN = "greaterThan",
    GREATER_THAN_OR_EQUAL = "greaterThanOrEqual",
    LESS_THAN = "lessThan",
    LESS_THAN_OR_EQUAL = "lessThanOrEqual",
    NOT_EQUALS = "notEqual"
  }
}
