import React from 'react';
import {
  IconButton,
  Popover,
  Stack,
  TextField,
  MenuItem,
  Button,
  Badge,
  Divider,
  IconButton as MuiIconButton,
  Autocomplete,
  Chip,
} from '@mui/material';
import { FilterList as FilterListIcon, Close as CloseIcon } from '@mui/icons-material';
import type { GridFilterModel, GridColDef } from '@mui/x-data-grid-premium';

interface StatusOption {
  value: string;
  label: string;
}

interface Props {
  columns: GridColDef[];
  filterModel: GridFilterModel;
  setFilterModel: (model: GridFilterModel) => void;
  statusOptions?: StatusOption[]; // for fgStatus label lookup & options
  debounceMs?: number;
}

type LocalFilterItem = {
  field: string;
  operator: string;
  value?: any;
  join?: 'AND' | 'OR'; // new: join operator (applies before this item, except first)
};

// helper operator lists
const TEXT_OPS = [
  { value: 'contains', label: 'contains' },
  { value: 'equals', label: 'equals' },
  { value: 'is empty', label: 'is empty' },
  { value: 'is not empty', label: 'is not empty' },
  { value: 'is any of', label: 'is any of' },
];
const NUMERIC_OPS = [
  { value: '=', label: '=' },
  { value: '>=', label: '>=' },
  { value: '<=', label: '<=' },
];
const STATUS_OPS = [
  { value: 'is', label: 'is' },
  { value: 'is not', label: 'is not' },
  { value: 'is any of', label: 'is any of' },
];
const DATE_OPS = [
  { value: 'is', label: 'is' },
  { value: 'is on or after', label: 'is on or after' },
  { value: 'is on or before', label: 'is on or before' },
];

const numericFields = new Set(['masaPajak', 'tahunPajak', 'dpp', 'pphDipotong']);
const dateFields = new Set(['created_at', 'updated_at']);

function getOperatorOptionsForField(field?: string) {
  if (!field) return TEXT_OPS;
  if (field === 'fgStatus') return STATUS_OPS;
  if (numericFields.has(field)) return NUMERIC_OPS;
  if (dateFields.has(field)) return DATE_OPS;
  return TEXT_OPS;
}

function defaultOperatorForField(field?: string) {
  if (!field) return 'contains';
  if (field === 'fgStatus') return 'is';
  if (numericFields.has(field)) return '=';
  if (dateFields.has(field)) return 'is';
  return 'contains';
}

// Memoized component
export const CustomFilterButton: React.FC<Props> = React.memo(
  ({ columns, filterModel, setFilterModel, statusOptions = [], debounceMs = 400 }) => {
    const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);

    const [localItems, setLocalItems] = React.useState<LocalFilterItem[]>(
      () => (filterModel?.items as any) ?? []
    );

    React.useEffect(() => {
      setLocalItems((filterModel?.items as any) ?? []);
    }, [filterModel?.items]);

    const debounceRef = React.useRef<number | null>(null);
    const clearDebounce = React.useCallback(() => {
      if (debounceRef.current !== null) {
        window.clearTimeout(debounceRef.current);
        debounceRef.current = null;
      }
    }, []);

    const applyImmediate = React.useCallback(
      (items: LocalFilterItem[]) => {
        clearDebounce();
        setFilterModel({ items: items as any });
      },
      [clearDebounce, setFilterModel]
    );

    const applyDebounced = React.useCallback(
      (items: LocalFilterItem[]) => {
        clearDebounce();
        debounceRef.current = window.setTimeout(() => {
          setFilterModel({ items: items as any });
          debounceRef.current = null;
        }, debounceMs) as unknown as number;
      },
      [clearDebounce, debounceMs, setFilterModel]
    );

    React.useEffect(() => clearDebounce, [clearDebounce]);

    const activeCount =
      Number(
        ((filterModel?.items as any) || []).filter((i: any) => {
          if (!i || !i.field) return false;
          const op = String(i.operator ?? '').toLowerCase();
          if (op === 'is empty' || op === 'is not empty') return true;
          if (op === 'is any of')
            return Array.isArray(i.value) ? (i.value as any[]).length > 0 : !!i.value;
          return i.value !== undefined && i.value !== '';
        }).length
      ) || 0;

    const getCol = React.useCallback(
      (field?: string) => columns.find((c) => c.field === field),
      [columns]
    );

    const buttonRef = React.useRef<HTMLButtonElement | null>(null);

    const handleClick = (e: React.MouseEvent<HTMLElement>) => {
      e.stopPropagation();
      if (!filterModel?.items?.length) {
        const init = [
          {
            field: columns[0]?.field ?? '',
            operator: defaultOperatorForField(columns[0]?.field),
            value: '',
            join: undefined,
          } as LocalFilterItem,
        ];
        setLocalItems(init);
      } else {
        setLocalItems((filterModel?.items as any) ?? []);
      }
      setAnchorEl(buttonRef.current);
    };

    const handleClose = () => {
      setAnchorEl(null);
    };

    const addFilter = React.useCallback(() => {
      setLocalItems((prev) => {
        const next = [
          ...(prev || []),
          {
            field: columns[0]?.field ?? '',
            operator: defaultOperatorForField(columns[0]?.field),
            value: '',
            join: 'AND', // default join for newly added filters
          } as LocalFilterItem,
        ];
        return next;
      });
    }, [columns]);

    const removeFilter = React.useCallback((index: number) => {
      setLocalItems((prev) => (prev || []).filter((_, i) => i !== index));
    }, []);

    const handleClearAll = React.useCallback(() => {
      clearDebounce();
      setLocalItems([]);
      setFilterModel({ items: [] });
    }, [clearDebounce, setFilterModel]);

    const updateFilter = React.useCallback(
      (index: number, key: keyof LocalFilterItem, value: any) => {
        setLocalItems((prev) => {
          const next = Array.isArray(prev) ? [...prev] : [];
          const old = next[index] ?? {
            field: columns[0]?.field ?? '',
            operator: defaultOperatorForField(columns[0]?.field),
            value: '',
            join: index === 0 ? undefined : 'AND',
          };
          let updated = { ...old, [key]: value };

          if (key === 'field') {
            const newField = value as string;
            const defOp = defaultOperatorForField(newField) as any;
            updated = { ...updated, field: newField, operator: defOp, value: '' };
            next[index] = updated;
            return next;
          }

          if (key === 'operator') {
            const op = String(value).toLowerCase();
            if (op === 'is empty' || op === 'is not empty') {
              updated = { ...updated, operator: value, value: '' };
              next[index] = updated;
              return next;
            }
            if (op === 'is any of') {
              if (!Array.isArray(updated.value)) updated.value = [];
              updated = { ...updated, operator: value };
              next[index] = updated;
              return next;
            }
            updated = { ...updated, operator: value, value: String(updated.value ?? '') };
            next[index] = updated;
            return next;
          }

          next[index] = updated;
          const items = next;
          const col = getCol(items[index].field as string);
          const isSingleSelect =
            !!col && (col.type === 'singleSelect' || Array.isArray((col as any).valueOptions));
          if (isSingleSelect) {
            applyImmediate(items);
          } else {
            applyDebounced(items);
          }
          return items;
        });
      },
      [applyDebounced, applyImmediate, columns, getCol]
    );

    const handleApply = React.useCallback(() => {
      clearDebounce();
      // Persist localItems to parent; keep join property so hook can use it
      setFilterModel({ items: localItems as any });
      setAnchorEl(null);
    }, [localItems, clearDebounce, setFilterModel]);

    return (
      <>
        <Badge badgeContent={activeCount} color="primary" overlap="circular">
          <IconButton
            size="small"
            ref={buttonRef}
            onMouseDown={(e) => e.stopPropagation()}
            onClick={handleClick}
            sx={{ color: '#123375' }}
            aria-label="filter"
          >
            <FilterListIcon />
          </IconButton>
        </Badge>

        <Popover
          open={Boolean(anchorEl)}
          anchorEl={anchorEl}
          onClose={handleClose}
          keepMounted
          anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
          transformOrigin={{ vertical: 'top', horizontal: 'right' }}
          PaperProps={{ sx: { p: 2, minWidth: 640, maxWidth: '95vw' } }}
        >
          <Stack gap={2}>
            {(localItems || []).map((item, idx) => {
              const colDef = getCol(item.field as string);
              const operatorOptions = getOperatorOptionsForField(item.field);
              const op = String(item.operator ?? defaultOperatorForField(item.field));

              const valueOptions: string[] =
                (colDef && (colDef as any).valueOptions) ||
                (colDef && colDef.type === 'singleSelect'
                  ? ((colDef as any).valueOptions ?? [])
                  : []);

              const statusVals = statusOptions.map((s) => s.value);

              const isNoValueOp = op === 'is empty' || op === 'is not empty';
              const isAnyOfOp = op === 'is any of';
              const isDateField = dateFields.has(item.field as string);
              const isNumericField = numericFields.has(item.field as string);
              const isStatusField = item.field === 'fgStatus';

              return (
                <Stack
                  key={idx}
                  direction="row"
                  spacing={1}
                  alignItems="center"
                  sx={{ width: '100%' }}
                >
                  {/* Join select (show for idx > 0) */}
                  {idx > 0 ? (
                    <TextField
                      select
                      size="small"
                      label=""
                      value={item.join ?? 'AND'}
                      onChange={(e) => updateFilter(idx, 'join', e.target.value as 'AND' | 'OR')}
                      sx={{ width: 72 }}
                      InputLabelProps={{ shrink: true }}
                    >
                      <MenuItem value="AND">AND</MenuItem>
                      <MenuItem value="OR">OR</MenuItem>
                    </TextField>
                  ) : (
                    <div style={{ width: 72 }} />
                  )}

                  {/* Column */}
                  <TextField
                    select
                    size="small"
                    label="Column"
                    value={item.field ?? ''}
                    onChange={(e) => updateFilter(idx, 'field', e.target.value)}
                    InputLabelProps={{ shrink: true }}
                    sx={{ minWidth: 220 }}
                  >
                    {columns.map((col) => (
                      <MenuItem key={String(col.field)} value={col.field}>
                        {col.headerName ?? String(col.field)}
                      </MenuItem>
                    ))}
                  </TextField>

                  {/* Operator */}
                  <TextField
                    select
                    size="small"
                    label="Operator"
                    value={op}
                    onChange={(e) => updateFilter(idx, 'operator', e.target.value)}
                    InputLabelProps={{ shrink: true }}
                    sx={{ minWidth: 200 }}
                  >
                    {operatorOptions.map((o) => (
                      <MenuItem key={o.value} value={o.value}>
                        {o.label}
                      </MenuItem>
                    ))}
                  </TextField>

                  {/* Value */}
                  {isNoValueOp ? (
                    <TextField
                      size="small"
                      label="Value"
                      placeholder="No value required"
                      value=""
                      disabled
                      InputLabelProps={{ shrink: true }}
                      sx={{ flex: 1, minWidth: 160 }}
                    />
                  ) : isAnyOfOp ? (
                    <Autocomplete
                      multiple
                      freeSolo
                      size="small"
                      options={
                        isStatusField ? statusVals : ((valueOptions as string[] | undefined) ?? [])
                      }
                      value={
                        Array.isArray(item.value) ? item.value : item.value ? [item.value] : []
                      }
                      onChange={(_, values) => {
                        updateFilter(idx, 'value', values);
                      }}
                      renderTags={(value: any[], getTagProps) =>
                        value.map((option: any, index: number) => (
                          <Chip
                            variant="outlined"
                            label={String(option)}
                            {...getTagProps({ index })}
                          />
                        ))
                      }
                      renderInput={(params) => (
                        <TextField
                          {...params}
                          label="Value(s)"
                          placeholder="Select values..."
                          InputLabelProps={{ shrink: true }}
                          sx={{ flex: 1, minWidth: 160 }}
                        />
                      )}
                      sx={{ flex: 1, minWidth: 160 }}
                    />
                  ) : isDateField ? (
                    <TextField
                      size="small"
                      label="Value"
                      type="date"
                      value={item.value ? String(item.value).slice(0, 10) : ''}
                      onChange={(e) => updateFilter(idx, 'value', e.target.value)}
                      InputLabelProps={{ shrink: true }}
                      sx={{ flex: 1, minWidth: 160 }}
                    />
                  ) : colDef &&
                    (colDef.type === 'singleSelect' ||
                      Array.isArray((colDef as any).valueOptions)) ? (
                    <TextField
                      select
                      size="small"
                      label="Value"
                      value={item.value ?? ''}
                      onChange={(e) => updateFilter(idx, 'value', e.target.value)}
                      InputLabelProps={{ shrink: true }}
                      sx={{ flex: 1, minWidth: 160 }}
                    >
                      {((colDef as any).valueOptions ?? (isStatusField ? statusVals : [])).map(
                        (opt: any) => (
                          <MenuItem key={String(opt)} value={opt}>
                            {isStatusField
                              ? (statusOptions.find((s) => s.value === opt)?.label ?? String(opt))
                              : String(opt)}
                          </MenuItem>
                        )
                      )}
                    </TextField>
                  ) : (
                    <TextField
                      size="small"
                      label="Value"
                      placeholder="Filter Value"
                      value={item.value ?? ''}
                      onChange={(e) => {
                        const v = e.target.value;
                        if (isNumericField) {
                          const digits = v.replace(/[^0-9]/g, '');
                          updateFilter(idx, 'value', digits);
                        } else {
                          updateFilter(idx, 'value', v);
                        }
                      }}
                      InputLabelProps={{ shrink: true }}
                      inputProps={isNumericField ? { inputMode: 'numeric', pattern: '[0-9]*' } : {}}
                      sx={{ flex: 1, minWidth: 160 }}
                    />
                  )}

                  <MuiIconButton
                    size="small"
                    onClick={(e) => {
                      e.stopPropagation();
                      removeFilter(idx);
                    }}
                  >
                    <CloseIcon fontSize="small" />
                  </MuiIconButton>
                </Stack>
              );
            })}

            <Divider />

            <Stack direction="row" justifyContent="space-between" alignItems="center">
              <Button
                size="small"
                variant="outlined"
                onClick={(e) => {
                  e.stopPropagation();
                  addFilter();
                }}
              >
                + Add filter
              </Button>

              <Stack direction="row" spacing={1}>
                <Button
                  size="small"
                  onClick={(e) => {
                    e.stopPropagation();
                    handleClearAll();
                  }}
                >
                  Clear
                </Button>

                <Button
                  size="small"
                  variant="contained"
                  onClick={(e) => {
                    e.stopPropagation();
                    handleApply();
                  }}
                >
                  Apply
                </Button>
              </Stack>
            </Stack>
          </Stack>
        </Popover>
      </>
    );
  }
);

export default CustomFilterButton;
