import * as React from "react";
import {
  Box,
  Button,
  Chip,
  Paper,
  TextField,
  Autocomplete,
  Typography,
} from "@mui/material";
import DoneIcon from "@mui/icons-material/Done";
import FilterListIcon from "@mui/icons-material/FilterList";
import { ResourceField, ResourceMode } from "../types/config";
import { FilterBarComponents } from "../types/overrides";
import { getFieldOptions, resolveTemplate } from "../utils/options";

export function FilterAutocomplete({
  options,
  value,
  label,
  onChange,
}: {
  options: string[];
  value: string[];
  label: string;
  onChange: (val: string[]) => void;
}) {
  const listboxRef = React.useRef<HTMLUListElement>(null);
  const scrollPosRef = React.useRef(0);
  const [open, setOpen] = React.useState(false);
  const [frozenValue, setFrozenValue] = React.useState<string[]>(value);

  const toggleDropdown = () => {
    setOpen(prev => {
      const next = !prev;
      setFrozenValue(value);
      return next;
    });
  };
  const sortedOptions = React.useMemo(() => {
    const sel = new Set(frozenValue);
    const picked: string[] = [];
    const rest: string[] = [];
    for (const o of options) {
      if (sel.has(o)) picked.push(o);
      else rest.push(o);
    }
    return [...picked, ...rest];
  }, [options, frozenValue]);

  return (
    <Autocomplete
      multiple
      freeSolo
      disableCloseOnSelect
      open={open}
      onOpen={toggleDropdown}
      onClose={toggleDropdown}
      options={sortedOptions}
      value={value}
      getOptionKey={(option) => option}
      onChange={(_, val) => onChange(val.length > 0 ? val : [])}
      ListboxProps={{
        ref: listboxRef,
        onScroll: (e) => { scrollPosRef.current = (e.target as HTMLUListElement).scrollTop; },
      }}
      renderOption={(props, option, { selected }) => {
        const { key, ...rest } = props;
        return (
          <li key={key} {...rest}>
            {selected ? <DoneIcon sx={{ fontSize: 14, mr: 1, color: 'primary.main' }} /> : <Box sx={{ width: 22, mr: 1 }} />}
            {option}
          </li>
        );
      }}
      renderTags={(tagValue, getTagProps) => {
        const maxChips = 1;
        return (
          <>
            {tagValue.slice(0, maxChips).map((tag, index) => {
              const { key, ...tagProps } = getTagProps({ index });
              return <Chip
                key={key}
                {...tagProps}
                label={tag.length > 10 ? `${tag.slice(0, 8)}..` : tag}
                size="small"
                onClick={toggleDropdown}
                sx={{ cursor: 'pointer' }}
              />;
            })}
            {tagValue.length > maxChips && (
              <Chip
                label={`+${tagValue.length - maxChips}`}
                size="small"
                onClick={toggleDropdown}
                sx={{ cursor: 'pointer' }}
              />
            )}
          </>
        );
      }}
      renderInput={(params) => <TextField {...params} placeholder={`Add ${label}...`} />}
      sx={{ '& .MuiOutlinedInput-root': { minHeight: '3rem', py: 0.5 } }}
    />
  );
}

function extractOptions(
  fieldName: string,
  field: ResourceField,
  data: any[]
): string[] {
  const values = new Set<string>();

  if (field.type === 'enum') {
    return getFieldOptions(field).map(o => o.value);
  }
  if (!data) return [];

  const pull = (item: any): string | null => {
    if (item == null) return null;
    if (typeof item === "string") return item;
    if (typeof item !== "object") return String(item);

    if (field.enumOption?.value) return resolveTemplate(field.enumOption.value, item);

    if (fieldName == 'payee') debugger;
    const df = field.displayField;
    if (!df) return null;

    if (Array.isArray(df)) {
      const parts = df.map((k) => item[k]).filter((v) => v != null);
      if (parts.length > 0) return parts.join(" ");
      return null;
    }
    const v = item[df];
    if (v != null) return String(v);

    return null;
  };

  for (const row of data) {
    const v = row[fieldName];
    if (v == null) continue;

    if (Array.isArray(v)) {
      for (const el of v) {
        const label = pull(el);
        if (label) values.add(label);
      }
    } else {
      const label = pull(v);
      if (label) values.add(label);
    }
  }

  // console.log('extracted', fieldName, Array.from(values).sort())
  return Array.from(values).sort();
}

function renderFilterInput(
  fieldName: string,
  field: ResourceField,
  options: string[],
  value: any,
  onChange: (key: string, val: any) => void,
  components?: FilterBarComponents,
) {
  const CustomInput = components?.filterInputs?.[fieldName];
  if (CustomInput) {
    return <CustomInput field={field} value={value} onChange={(val) => onChange("value", val)} options={options} />;
  }

  const filterType = field.filterType;

  if (filterType === "number-range") {
    const rangeVal = (value as { min?: string; max?: string }) || {};
    return (
      <Box sx={{ display: "flex", gap: 1 }}>
        <TextField type="number" placeholder="Min" size="small" value={rangeVal.min ?? ""}
          onChange={(e) => onChange("min", e.target.value || undefined)} sx={{ width: 100 }} />
        <TextField type="number" placeholder="Max" size="small" value={rangeVal.max ?? ""}
          onChange={(e) => onChange("max", e.target.value || undefined)} sx={{ width: 100 }} />
      </Box>
    );
  }

  if (filterType === "date-range") {
    const rangeVal = (value as { start?: string; end?: string }) || {};
    return (
      <Box sx={{ display: "flex", gap: 1 }}>
        <TextField type="datetime-local" placeholder="From" size="small" value={rangeVal.start ?? ""}
          onChange={(e) => onChange("start", e.target.value || undefined)} InputLabelProps={{ shrink: true }} sx={{ width: 170 }} />
        <TextField type="datetime-local" placeholder="To" size="small" value={rangeVal.end ?? ""}
          onChange={(e) => onChange("end", e.target.value || undefined)} InputLabelProps={{ shrink: true }} sx={{ width: 170 }} />
      </Box>
    );
  }

  const selected = Array.isArray(value) ? value : [];

  return (
    <FilterAutocomplete
      options={options}
      value={selected}
      label={field.label}
      onChange={(val) => onChange("value", val.length > 0 ? val : undefined)}
    />
  );
}

export interface FilterBarProps {
  fields: Record<string, ResourceField>;
  filterableFields: string[];
  mode: ResourceMode;
  data?: any[];
  appliedValues: Record<string, any>;
  onApply: (values: Record<string, any>) => void;
  onClear: () => void;
  components?: FilterBarComponents;
}

export default function FilterBar({
  fields,
  filterableFields,
  data,
  appliedValues,
  onApply,
  onClear,
  components: filterComponents,
}: FilterBarProps) {
  const [open, setOpen] = React.useState(false);
  const [draft, setDraft] = React.useState<Record<string, any>>(() => ({ ...appliedValues }));

  React.useEffect(() => {
    if (!open) setDraft({ ...appliedValues });
  }, [appliedValues, open]);

  if (!filterableFields || filterableFields.length === 0) return null;

  const activeCount = Object.keys(appliedValues).filter((k) => {
    const v = appliedValues[k];
    if (v == null || v === "") return false;
    if (typeof v === "object" && Object.values(v).every((x) => x == null || x === "")) return false;
    return true;
  }).length;

  const handleApply = () => onApply({ ...draft });
  const handleClear = () => {
    setDraft({});
    onClear();
  };

  const updateDraft = (fieldName: string, key: string, val: any) => {
    setDraft((prev) => {
      if (key === "value") {
        return { ...prev, [fieldName]: val };
      }
      const existing = prev[fieldName] || {};
      return { ...prev, [fieldName]: { ...existing, [key]: val } };
    });
  };

  return (
    <Paper variant="outlined" sx={{ mb: 2, borderRadius: 2, overflow: "hidden" }}>
      <Box
        sx={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          px: 2,
          py: 1,
          cursor: "pointer",
          "&:hover": { bgcolor: "action.hover" },
        }}
        onClick={() => setOpen((o) => !o)}
      >
        <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
          <FilterListIcon fontSize="small" color="action" />
          <Typography variant="subtitle2" fontWeight={600}>
            {open ? "Hide Filters" : "Show Filters"}
          </Typography>
        </Box>
        {activeCount > 0 && (
          <Typography variant="caption" color="primary" fontWeight={600}>
            {activeCount} active
          </Typography>
        )}
      </Box>

      {open && (
        <Box sx={{ px: 2, pb: 2, borderTop: "1px solid", borderColor: "divider", pt: 2 }}>
          <Box sx={{ display: "flex", flexWrap: "wrap", gap: 2, alignItems: "flex-end" }}>
            {filterableFields.map((fieldName) => {
              const field = fields[fieldName];
              if (!field) return null;

                const needsOptions = field.filterType === "autocomplete" || field.filterType === "multiselect";
              const options = needsOptions ? extractOptions(fieldName, field, data ?? []) : [];
              const raw = draft[fieldName];

              return (
                <Box key={fieldName} sx={{ display: "flex", flexDirection: "column", flex: { xs: '0 0 100%', sm: 1 }, minWidth: { sm: 200 } }}>
                  <Box sx={{ typography: "caption", mb: 0.5, color: "text.secondary" }}>
                    {field.label}
                  </Box>
                  {renderFilterInput(fieldName, field, options, raw, (key, val) =>
                    updateDraft(fieldName, key, val), filterComponents
                  )}
                </Box>
              );
            })}
          </Box>

          <Box sx={{ mt: 2, display: "flex", gap: 1 }}>
            <Button variant="contained" onClick={handleApply}>
              Apply
            </Button>
            <Button variant="outlined" onClick={handleClear}>
              Clear
            </Button>
          </Box>
        </Box>
      )}
    </Paper>
  );
}
