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' },
];

// numeric fields (include common variants/casing to be safe)
const numericFields = new Set([
  'masapajak',
  'masaPajak',
  'tahunpajak',
  'tahunPajak',
  'totaldpp',
  'dpp',
  'totaldpplain',
  'totaldpplain',
  'totalppn',
  'ppn',
  'totalppnbm',
  'ppnbm',
  'jumlahuangmuka',
  'jumlahUangMuka',
]);

// date fields
const dateFields = new Set([
  'tanggalfaktur',
  'tanggalapproval',
  'created_at',
  'updated_at',
  'tanggal_approval',
]);

// status-like fields
const statusFields = new Set(['fgStatus', 'jenisInvoice', 'statusfaktur']);

function getOperatorOptionsForField(field?: string) {
  if (!field) return TEXT_OPS;
  if (statusFields.has(field)) 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 (statusFields.has(field)) 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);
          // === PERBAIKAN: jangan kecualikan 'jenisInvoice' di sini,
          // treat jenisInvoice as singleSelect jika definisinya ada
          const isSingleSelect =
            !!col &&
            (col.type === 'singleSelect' ||
              Array.isArray((col as any).valueOptions) ||
              items[index].field === 'jenisInvoice');

          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]);

    const JenisInvoiceOption = [
      { value: 'uang-muka', label: 'Uang Muka' },
      { value: 'pelunasan', label: 'Pelunasan' },
      { value: 'full-payment', label: 'Full Payment' },
    ];

    const AllStatusOptions: Record<string, { value: string; label: string }[]> = {
      fgStatus: statusOptions ?? [],
      statusfaktur: statusOptions ?? [],
      stupdate: statusOptions ?? [],
      isUsed: statusOptions ?? [],
      jenisInvoice: JenisInvoiceOption, // ⬅ tambahkan ini
    };

    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));

              // Determine raw options (either from jenisInvoice mapping OR column def)
              let rawValueOptions: any[] = [];
              if (item.field === 'jenisInvoice') {
                rawValueOptions = AllStatusOptions['jenisInvoice'] ?? [];
              } else if (
                colDef?.type === 'singleSelect' ||
                Array.isArray((colDef as any).valueOptions)
              ) {
                rawValueOptions = (colDef as any).valueOptions ?? [];
              }

              // normalize into { value, label } array
              const normalizedValueOptions = (rawValueOptions || []).map((opt: any) => {
                if (opt && typeof opt === 'object' && 'value' in opt && 'label' in opt) {
                  return { value: opt.value, label: opt.label };
                }
                return { value: opt, label: String(opt) };
              });

              // if status-like mapping exists in AllStatusOptions, prefer that for labels
              const realStatusOptions = (AllStatusOptions[item.field as string] ??
                statusOptions) as StatusOption[];
              const statusVals = realStatusOptions.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 = statusFields.has(item.field as string);

              // decide if we should render as select (singleSelect)
              const isSelectField =
                normalizedValueOptions.length > 0 || (colDef && colDef.type === 'singleSelect');

              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 : normalizedValueOptions.map((o) => o.value)
                      }
                      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 }}
                    />
                  ) : isSelectField ? (
                    <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 }}
                    >
                      {/* prefer normalizedValueOptions if available, otherwise fallback to status mapping */}
                      {(normalizedValueOptions.length > 0
                        ? normalizedValueOptions
                        : realStatusOptions.map((s) => ({ value: s.value, label: s.label }))
                      ).map((opt: any) => (
                        <MenuItem key={String(opt.value)} value={opt.value}>
                          {String(opt.label)}
                        </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;
