import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, Output, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { FilterGroup, SearchFilterState } from '../../../../../core/search/models/search.model';
import { TranslatePipe } from '../../../../../i18n/translate.pipe';

const RANGE_DEBOUNCE_MS = 350;

@Component({
  selector: 'app-catalog-filters-panel',
  standalone: true,
  imports: [FormsModule, TranslatePipe],
  templateUrl: './filters-panel.component.html',
  styleUrls: ['./filters-panel.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CatalogFiltersPanelComponent implements OnDestroy {
  @Input() definitions: FilterGroup[] = [];
  @Input() state: SearchFilterState = { values: {}, ranges: {}, toggles: {} };

  @Output() stateChange = new EventEmitter<SearchFilterState>();

  private readonly debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();

  ngOnDestroy(): void {
    for (const timer of this.debounceTimers.values()) {
      clearTimeout(timer);
    }
  }

  readonly collapsed = signal<Record<string, boolean>>({});

  toggleGroup(filterId: string): void {
    this.collapsed.update(current => ({
      ...current,
      [filterId]: !current[filterId],
    }));
  }

  isCollapsed(filterId: string): boolean {
    return this.collapsed()[filterId] ?? false;
  }

  shouldRenderFilter(filter: FilterGroup): boolean {
    if (!filter.enabled) {
      return false;
    }

    if (filter.type === 'range' || filter.type === 'slider') {
      const min = Number(filter.min ?? 0);
      const max = Number(filter.max ?? 0);
      return Number.isFinite(min) && Number.isFinite(max) && min < max;
    }

    if (filter.type === 'toggle') {
      return true;
    }

    return (filter.options?.length ?? 0) > 1;
  }

  isSelected(filterId: string, optionValue: string): boolean {
    return (this.state.values[filterId] ?? []).includes(optionValue);
  }

  toggleOption(filterId: string, optionValue: string): void {
    const current = this.state.values[filterId] ?? [];
    const next = current.includes(optionValue)
      ? current.filter(value => value !== optionValue)
      : [...current, optionValue];

    this.stateChange.emit({
      ...this.state,
      values: {
        ...this.state.values,
        [filterId]: next
      }
    });
  }

  selectSingleOption(filterId: string, optionValue: string): void {
    this.stateChange.emit({
      ...this.state,
      values: {
        ...this.state.values,
        [filterId]: [optionValue],
      },
    });
  }

  updateRange(filterId: string, key: 'min' | 'max', rawValue: string): void {
    const value = rawValue.trim().length ? Number(rawValue) : undefined;

    this.debounce(`range:${filterId}:${key}`, () => {
      const current = this.state.ranges[filterId] ?? {};
      this.stateChange.emit({
        ...this.state,
        ranges: {
          ...this.state.ranges,
          [filterId]: {
            ...current,
            [key]: Number.isFinite(value as number) ? value : undefined
          }
        }
      });
    });
  }

  updateSlider(filterId: string, value: string): void {
    const numeric = Number(value);

    this.debounce(`slider:${filterId}`, () => {
      this.stateChange.emit({
        ...this.state,
        ranges: {
          ...this.state.ranges,
          [filterId]: {
            ...this.state.ranges[filterId],
            max: Number.isFinite(numeric) ? numeric : undefined,
          },
        },
      });
    });
  }

  /** Debounces range/slider input so full catalog filter recompute doesn't run on every keystroke/drag event. */
  private debounce(key: string, action: () => void): void {
    const existing = this.debounceTimers.get(key);
    if (existing) {
      clearTimeout(existing);
    }
    this.debounceTimers.set(key, setTimeout(() => {
      this.debounceTimers.delete(key);
      action();
    }, RANGE_DEBOUNCE_MS));
  }

  updateToggle(filterId: string, checked: boolean): void {
    this.stateChange.emit({
      ...this.state,
      toggles: {
        ...this.state.toggles,
        [filterId]: checked
      }
    });
  }
}
