import { Box, Stack, type Theme, Typography } from '@mui/material';

import { AttributePicker } from './components/AttributePicker';
import { conditionsForType } from './constants';
import { darkBackground, gray } from '../../../themes/common';
import { FilterRow } from './components/FilterRow';
import { filterFromSearchQuery, nextUid } from './utils/filterPayload';
import { HostkeyIncludeExclude } from './components/HostkeyIncludeExclude';
import type { CfeAttribute, EntriesFilter, FilterRule, InventoryFilterState, InventoryMapping } from './types';

export interface InventoryFilterProps {
  disabled?: boolean;
  // Show the "Classes" section + host-search option in the attribute picker.
  includeClasses?: boolean;
  // Available inventory attributes (CFE_mapping) — from the shared inventory slice.
  mapping: InventoryMapping;
  onChange: (next: InventoryFilterState) => void;
  // Optional actions rendered top-right of the panel (e.g. Reset / select-group).
  toolbarActions?: React.ReactNode;
  // The controlled filter state (filters + entriesFilter).
  value: InventoryFilterState;
}

// Gray panel behind the whole filter body.
const panelSx = (theme: Theme) => ({
  backgroundColor: theme.palette.mode === 'dark' ? darkBackground[50] : gray[100],
  padding: '12px 12px 8px 12px'
});

// Controlled filter editor: attribute/class rules + an include/exclude-by-host
// widget. Emits the whole updated state via `onChange`.
export const InventoryFilter = ({ value, onChange, mapping, includeClasses = false, disabled = false, toolbarActions }: InventoryFilterProps) => {
  const setFilters = (filters: FilterRule[]) => onChange({ ...value, filters });
  const setEntries = (entriesFilter: EntriesFilter) => onChange({ ...value, entriesFilter });

  const addAttribute = (attribute: CfeAttribute) => {
    const type = attribute.type || 'string';
    setFilters([...value.filters, { ...attribute, uid: nextUid(), type, condition: conditionsForType(type)[0].value, value: undefined }]);
  };

  const addClass = (className: string) => setFilters([...value.filters, { uid: nextUid(), type: 'class', value: className, condition: 'matches' }]);

  const addHostSearch = (query: string) => setFilters([...value.filters, filterFromSearchQuery(query)]);

  const updateFilter = (uid: string, next: FilterRule) => setFilters(value.filters.map(filter => (filter.uid === uid ? next : filter)));

  const removeFilter = (uid: string) => setFilters(value.filters.filter(filter => filter.uid !== uid));

  // Swap a rule's attribute in place; condition resets to the new type's default.
  const changeAttribute = (uid: string, attribute: CfeAttribute) => {
    const type = attribute.type || 'string';
    updateFilter(uid, { ...attribute, uid, type, condition: conditionsForType(type)[0].value, value: undefined });
  };

  const changeToClass = (uid: string, className: string) => updateFilter(uid, { uid, type: 'class', value: className, condition: 'matches' });

  return (
    <Box sx={panelSx}>
      <Stack direction="row" spacing={2} sx={{ alignItems: 'flex-start', justifyContent: 'space-between', mb: '12px' }}>
        <Box>
          {includeClasses && (
            <Typography variant="hint" color="text.primary">
              You can filter hosts using rules for both classes and inventory attributes.
            </Typography>
          )}
        </Box>
        {toolbarActions && <Box sx={{ flexShrink: 0 }}>{toolbarActions}</Box>}
      </Stack>

      <Stack spacing={1}>
        {value.filters.map(filter => (
          <FilterRow
            key={filter.uid}
            filter={filter}
            disabled={disabled}
            mapping={mapping}
            includeClasses={includeClasses}
            onChange={next => updateFilter(filter.uid, next)}
            onChangeAttribute={attribute => changeAttribute(filter.uid, attribute)}
            onChangeClass={className => changeToClass(filter.uid, className)}
            onRemove={() => removeFilter(filter.uid)}
          />
        ))}
      </Stack>

      <AttributePicker
        mapping={mapping}
        includeClasses={includeClasses}
        disabled={disabled}
        onSelectAttribute={addAttribute}
        onSelectClass={addClass}
        onHostSearch={addHostSearch}
      />

      <HostkeyIncludeExclude entriesFilter={value.entriesFilter} otherFiltersApplied={value.filters.length > 0} disabled={disabled} onChange={setEntries} />
    </Box>
  );
};
