/* eslint-disable react-refresh/only-export-components */
import { type BaseGridColumn, type GridCell, GridCellKind } from '@glideapps/glide-data-grid';
import { ActionIcon, Select, Stack, TextInput } from '@mantine/core';
import { useDebouncedValue } from '@mantine/hooks';
import { IconX } from '@tabler/icons-react';
import { type ReactNode, useEffect, useState } from 'react';

import type { FilterOption, FilterOptionOperator, GridlerStoreState } from './GridlerStore';

export type GridCellLoose = {
  kind: GridCellKind | string;
} & Omit<GridCell, 'allowOverlay' | 'kind'>;

export interface GridlerColumn extends Partial<BaseGridColumn> {
  Cell?: (
    row: any,
    col: number,
    colIndx: string,
    value: any,
    storeState: GridlerStoreState
  ) => Partial<GridCellLoose>;
  defaultIcon?: string;
  disableFilter?: boolean;
  disableMove?: boolean;
  disableResize?: boolean;
  disableSearch?: boolean;
  disableSort?: boolean;
  getMenuItems?: (
    id: string,
    storeState: any,
    row?: any,
    col?: GridlerColumn,
    defaultItems?: Array<any>
  ) => Array<any>;
  id: string;
  maxWidth?: number;
  minWidth?: number;
  tooltip?: ((buffer: any, row: number, col: number) => ReactNode) | string;
  virtual?: boolean;
  width?: number;
}

export const FilterOperators: Array<{ label: string; value: FilterOptionOperator }> = [
  { label: 'Contains', value: 'contains' },
  { label: 'Equal', value: 'eq' },
  { label: 'Not Equal', value: 'neq' },
  { label: 'Greater Than', value: 'gt' },
  { label: 'Greater Than or Equal', value: 'gte' },
  { label: 'Less Than', value: 'lt' },
  { label: 'Less Than or Equal', value: 'lte' },
];

export interface ColumnFilterSetProps {
  column: GridlerColumn;
  options?: Partial<FilterOption>;
  storeState: GridlerStoreState;
}

export type GridlerColumns = Array<GridlerColumn>;

export const ColumnFilterInput = (props: ColumnFilterSetProps) => {
  const filterIndex =
    props.storeState?.colFilters?.findIndex((f) => f.id === props.column.id) ?? -1;
  const filter = props.storeState?.colFilters?.[filterIndex] ?? { id: props.column.id, value: '' };

  const [filterValue, setFilterValue] = useState<string>(filter?.value ?? '');
  const [defferedFilterValue] = useDebouncedValue(filterValue, 900);

  useEffect(() => {
    props.storeState.setStateFN('colFilters', (state) => {
      const idx = state?.findIndex((f) => f.id === props.column.id) ?? -1;

      const filters = state ?? [];
      if (idx >= 0) {
        filters[idx] = {
          ...filters[idx],
          ...props.options,
          id: props.column.id,
          value: defferedFilterValue,
        };
      } else {
        filters.push({
          operator: 'contains',
          ...props.options,
          id: props.column.id,
          value: defferedFilterValue,
        });
      }

      return filters;
    });
  }, [defferedFilterValue, props.column.id, props.options, props.storeState]);

  return (
    <TextInput
      onChange={(e) => setFilterValue(e.target.value)}
      rightSection={
        <ActionIcon color="gray" onClick={() => setFilterValue('')} variant="filled">
          <IconX color="red" />
        </ActionIcon>
      }
      value={filterValue ?? filter?.value}
    />
  );
};

export const ColumnFilterInputOperator = (props: ColumnFilterSetProps) => {
  const filterIndex =
    props.storeState?.colFilters?.findIndex((f) => f.id === props.column.id) ?? -1;
  const filter = props.storeState?.colFilters?.[filterIndex] ?? {
    id: props.column.id,
    operator: 'contains',
  };

  const [filterValue, setFilterValue] = useState<FilterOptionOperator>(
    filter?.operator ?? 'contains'
  );
  const [defferedFilterValue] = useDebouncedValue(filterValue, 900);

  useEffect(() => {
    props.storeState.setStateFN('colFilters', (state) => {
      const idx = state?.findIndex((f) => f.id === props.column.id) ?? -1;

      const filters = state ?? [];
      if (idx >= 0) {
        filters[idx] = {
          ...filters[idx],
          ...props.options,
          id: props.column.id,
          operator: defferedFilterValue,
        };
      } else {
        filters.push({
          ...props.options,
          id: props.column.id,
          operator: defferedFilterValue,
          value: '',
        });
      }

      return filters;
    });
  }, [defferedFilterValue, props.column.id, props.options, props.storeState]);

  return (
    <Select
      comboboxProps={{ withinPortal: false }}
      data={FilterOperators}
      maxDropdownHeight={150}
      onChange={(value) => setFilterValue(value as any)}
      placeholder="Operator"
      searchable
      value={filterValue ?? filter?.operator}
      withScrollArea
    />
  );
};

export const ColumnFilterSet = (props: ColumnFilterSetProps) => {
  return (
    <Stack onClick={(e) => e.stopPropagation()}>
      <ColumnFilterInputOperator {...props} />
      <ColumnFilterInput {...props} />
    </Stack>
  );
};
