import { initFilterDrawer } from '../components/app-filter-drawer.js';
import { initActiveFilterChips } from '../components/app-active-filter-chips.js';

const debounce = (fn, delay = 250) => {
  let timer = null;
  return (...args) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => fn(...args), delay);
  };
};

export function initListFilterExperience(options = {}) {
  const {
    gridConfig,
    drawerRoot = document,
    drawer = {},
    live = {},
    chips = {},
    preserveFilterParamsOnReset = [],
    buildChips = () => [],
    removeChip = null,
    clearAllState = null,
    watchInputs = []
  } = options;

  if (!gridConfig || typeof gridConfig.captureAppliedState !== 'function') {
    return null;
  }

  let openSnapshot = null;
  let drawerDirtyDebounce = null;
  const announceUpdated = () => {
    document.dispatchEvent(new CustomEvent('app:filters-updated'));
  };
  const liveRegion = typeof live.regionSelector === 'string'
    ? document.querySelector(live.regionSelector)
    : null;
  const announceLive = (message) => {
    if (!liveRegion) {return;}
    const text = String(message || '').trim();
    if (text === '') {return;}
    liveRegion.textContent = '';
    requestAnimationFrame(() => {
      liveRegion.textContent = text;
    });
  };
  const normalizeComparable = (value) => {
    if (Array.isArray(value)) {
      return value
        .map((item) => String(item ?? '').trim())
        .filter(Boolean)
        .sort()
        .join('|');
    }
    return String(value ?? '').trim();
  };
  const countDraftChanges = (appliedState, draftState) => {
    const appliedFilters = appliedState?.filters && typeof appliedState.filters === 'object'
      ? appliedState.filters
      : {};
    const draftFilters = draftState?.filters && typeof draftState.filters === 'object'
      ? draftState.filters
      : {};

    let changed = 0;
    if (normalizeComparable(appliedState?.search || '') !== normalizeComparable(draftState?.search || '')) {
      changed += 1;
    }

    const keys = new Set([...Object.keys(appliedFilters), ...Object.keys(draftFilters)]);
    keys.forEach((key) => {
      if (normalizeComparable(appliedFilters[key] ?? '') !== normalizeComparable(draftFilters[key] ?? '')) {
        changed += 1;
      }
    });
    return changed;
  };

  const countActiveDraftFilters = (draftState) => {
    const filters = draftState?.filters && typeof draftState.filters === 'object'
      ? draftState.filters
      : {};
    const ignoredParams = new Set(
      Array.isArray(drawer?.countExcludeParams)
        ? drawer.countExcludeParams.map((item) => String(item ?? '').trim()).filter(Boolean)
        : []
    );

    let count = 0;
    Object.entries(filters).forEach(([param, rawValue]) => {
      if (ignoredParams.has(param)) {return;}

      if (Array.isArray(rawValue)) {
        count += rawValue
          .map((value) => String(value ?? '').trim())
          .filter(Boolean)
          .length;
        return;
      }

      const value = String(rawValue ?? '').trim();
      if (value === '' || value === 'all') {return;}
      if (value.includes(',')) {
        count += value
          .split(',')
          .map((item) => item.trim())
          .filter(Boolean)
          .length;
        return;
      }
      count += 1;
    });

    return count;
  };

  const chipsController = initActiveFilterChips({
    container: chips.container,
    removeButtonLabel: chips.removeButtonLabel || 'Remove filter',
    clearAllLabel: chips.clearAllLabel || 'Clear all filters',
    onRemove: async (chip) => {
      if (typeof removeChip !== 'function') {return;}
      const current = gridConfig.captureAppliedState();
      const next = removeChip(chip, current);
      if (!next || typeof next !== 'object') {return;}
      gridConfig.restoreAppliedState(next);
      if (typeof gridConfig.applyFilters === 'function') {
        gridConfig.applyFilters({ resetPage: true, urlHistoryMode: 'push' });
      } else {
        gridConfig.updateGrid({ resetPage: true, urlHistoryMode: 'push' });
      }
      announceUpdated();
      announceLive(live.removeMessage || '');
      renderChips();
    },
    onClearAll: async () => {
      if (typeof clearAllState === 'function') {
        const current = gridConfig.captureAppliedState();
        const next = clearAllState(current);
        if (next && typeof next === 'object') {
          gridConfig.restoreAppliedState(next);
          if (typeof gridConfig.applyFilters === 'function') {
            gridConfig.applyFilters({ resetPage: true, urlHistoryMode: 'push' });
          } else {
            gridConfig.updateGrid({ resetPage: true, urlHistoryMode: 'push' });
          }
          announceUpdated();
          announceLive(live.clearedMessage || '');
          renderChips();
        }
        return;
      }

      if (typeof gridConfig.resetFilters === 'function') {
        gridConfig.resetFilters({
          resetPage: true,
          urlHistoryMode: 'push',
          preserveFilterParams: preserveFilterParamsOnReset
        });
        announceUpdated();
        announceLive(live.clearedMessage || '');
        renderChips();
      }
    }
  });

  const renderChips = () => {
    const state = gridConfig.captureAppliedState();
    if (chipsController) {
      chipsController.render(buildChips(state));
    }
    if (drawerController && typeof drawerController.setTriggerCount === 'function') {
      drawerController.setTriggerCount(countActiveDraftFilters(state));
    }
  };

  const getDrawerDraftState = () => {
    if (typeof gridConfig.captureDraftState === 'function') {
      return gridConfig.captureDraftState();
    }
    return gridConfig.captureAppliedState();
  };

  const applyDirtyUi = (immediate = false) => {
    if (!drawerController || typeof drawerController.setApplyEnabled !== 'function') {
      return;
    }
    const run = () => {
      const baseState = openSnapshot || gridConfig.captureAppliedState();
      const draftState = getDrawerDraftState();
      const changedCount = countDraftChanges(baseState, draftState);
      const activeCount = countActiveDraftFilters(draftState);
      drawerController.setApplyEnabled(changedCount > 0);
      if (typeof drawerController.setApplyCount === 'function') {
        drawerController.setApplyCount(activeCount);
      }
    };

    if (immediate) {
      run();
      return;
    }
    if (drawerDirtyDebounce) {
      clearTimeout(drawerDirtyDebounce);
    }
    drawerDirtyDebounce = setTimeout(run, 120);
  };

  const drawerController = initFilterDrawer({
    root: drawerRoot,
    drawerSelector: drawer.drawerSelector || '[data-filter-drawer]',
    openSelector: drawer.openSelector || '[data-filter-drawer-open]',
    closeSelector: drawer.closeSelector || '[data-filter-drawer-close]',
    applySelector: drawer.applySelector || '[data-filter-drawer-apply]',
    resetSelector: drawer.resetSelector || '[data-filter-drawer-reset]',
    onOpen: () => {
      openSnapshot = gridConfig.captureAppliedState();
      gridConfig.restoreAppliedState(openSnapshot);
      applyDirtyUi(true);
    },
    onDiscard: () => {
      if (!openSnapshot) {return;}
      gridConfig.restoreAppliedState(openSnapshot);
      if (typeof drawerController?.setApplyEnabled === 'function') {
        drawerController.setApplyEnabled(false);
      }
      if (typeof drawerController?.setApplyCount === 'function') {
        drawerController.setApplyCount(0);
      }
      openSnapshot = null;
    },
    onApply: async () => {
      const baseState = openSnapshot || gridConfig.captureAppliedState();
      const draftState = getDrawerDraftState();
      const changedCount = countDraftChanges(baseState, draftState);
      if (changedCount <= 0) {
        applyDirtyUi(true);
        return false;
      }

      if (typeof gridConfig.applyFilters === 'function') {
        gridConfig.applyFilters({ resetPage: true, urlHistoryMode: 'push' });
      } else {
        gridConfig.updateGrid({ resetPage: true, urlHistoryMode: 'push' });
      }
      openSnapshot = null;
      announceUpdated();
      announceLive(live.appliedMessage || '');
      renderChips();
      return true;
    },
    onReset: async () => {
      if (typeof gridConfig.resetFilters !== 'function') {return;}
      gridConfig.resetFilters({
        resetPage: true,
        urlHistoryMode: 'push',
        preserveFilterParams: preserveFilterParamsOnReset
      });
      openSnapshot = gridConfig.captureAppliedState();
      announceUpdated();
      renderChips();
    }
  });

  if (drawerController?.drawer) {
    const drawerFields = Array.from(
      drawerController.drawer.querySelectorAll('input, select, textarea')
    );
    drawerFields.forEach((field) => {
      if (field.dataset.drawerDirtyBound === '1') {return;}
      field.dataset.drawerDirtyBound = '1';
      field.addEventListener('input', () => applyDirtyUi(false));
      field.addEventListener('change', () => applyDirtyUi(false));
    });
  }

  watchInputs
    .map((input) => (typeof input === 'string' ? document.querySelector(input) : input))
    .filter(Boolean)
    .forEach((input) => {
      input.addEventListener('input', debounce(() => {
        renderChips();
      }, 300));
      input.addEventListener('change', () => {
        renderChips();
      });
    });

  document.addEventListener('app:filters-updated', () => {
    renderChips();
  });

  renderChips();

  return {
    drawer: drawerController,
    renderChips
  };
}
