import { Component, EventEmitter, Input, OnInit, OnDestroy, Output } from '@angular/core';
import { ListColDefinition } from "@app/_components/list/list-col-definition";
import { Subject, debounceTime, takeUntil } from 'rxjs';
import {filter} from "rxjs/operators";

interface FilterState {
    name: string;
    field: string;
    type: string;
    value: any;
    active: boolean;
    subResource?: string;
    options?: string[];
}

interface NumberInput {
    name: string;
    field: string;
    boundType: 'min' | 'max';
    value: number | null;
    subResource?: string;
}

@Component({
    selector: 'app-filter-bar',
    templateUrl: './filter-bar.component.html',
    styleUrls: ['./filter-bar.component.scss']
})
export class FilterBarComponent implements OnInit, OnDestroy {
    @Input() public listColDefinitions!: ListColDefinition[];
    @Input() public filterConfig!: string | null;
    @Output() public filterInit = new EventEmitter<{filters: Record<string, any>, activeCount: number}>();
    @Output() public filterChanged = new EventEmitter<{filters: Record<string, any>, activeCount: number}>();
    @Output() public filterSave = new EventEmitter();

    public static readonly FILTER_TYPE_BOOLEAN: string = 'boolean';
    public static readonly FILTER_TYPE_TEXT: string = 'text';
    public static readonly FILTER_TYPE_DATE: string = 'date';
    public static readonly FILTER_TYPE_NUMBER: string = 'number';
    public static readonly FILTER_TYPE_CHECKBOXES: string = 'checkboxes';

    public filterStates: FilterState[] = [];

    private numberInputSubject = new Subject<NumberInput>();
    private textInputSubject = new Subject<{name: string, field: string, value: string, subResource?: string}>();
    private destroy$ = new Subject<void>();

    ngOnInit(): void {
        this.initializeFilterStates();
        this.setupNumberInputDebounce();
        this.setupTextInputDebounce();
    }

    ngOnDestroy(): void {
        this.destroy$.next();
        this.destroy$.complete();
    }

    private countActiveFilters(): number {
        return this.filterStates.filter(state => state.active).length;
    }

    private initializeFilterStates(): void {
        let filterSettingsObj: { [key: string]: any } = {};
        if (this.filterConfig !== null) {
            filterSettingsObj = JSON.parse(this.filterConfig);
        }
        this.filterStates = this.listColDefinitions
            .filter(col => col.filterType)
            .map(col => {
                let value = this.getInitialValueForType(col.filterType || '');
                let active = false;
                if (col.field !== undefined && filterSettingsObj.hasOwnProperty(col.field)) {
                    value = filterSettingsObj[col.field];
                    active = true;
                }
                const filterState: FilterState = {
                    name: col.name,
                    field: col.field || '',
                    type: col.filterType || '',
                    value: value,
                    active: active,
                    subResource: col.subResource,
                    options: col.filterOptions
                };
                return filterState;
            });
        const activeFilters: Record<string, any> = this.getActiveFilters();
        const activeCount = this.countActiveFilters();
        this.filterInit.emit({ filters: activeFilters, activeCount });
    }

    private setupNumberInputDebounce(): void {
        this.numberInputSubject.pipe(
            debounceTime(300),
            takeUntil(this.destroy$)
        ).subscribe(input => {
            this.updateNumberFilter(input.name, input.boundType, input.value);
        });
    }

    private setupTextInputDebounce(): void {
        this.textInputSubject.pipe(
            debounceTime(300),
            takeUntil(this.destroy$)
        ).subscribe(({field, value, subResource}) => {
            this.updateTextFilter(field, value, subResource);
        });
    }

    private getInitialValueForType(type: string, options?: string[]): any {
        switch (type) {
            case FilterBarComponent.FILTER_TYPE_BOOLEAN:
                return false;
            case FilterBarComponent.FILTER_TYPE_TEXT:
                return '';
            case FilterBarComponent.FILTER_TYPE_DATE:
                return { start: null, end: null };
            case FilterBarComponent.FILTER_TYPE_NUMBER:
                return { min: null, max: null };
            case FilterBarComponent.FILTER_TYPE_CHECKBOXES:
                if (options) {
                    return options.reduce((acc, option) => {
                        acc[option] = false;
                        return acc;
                    }, {} as {[key: string]: boolean});
                }
                return {};
            default:
                return null;
        }
    }

    private findFilterState(colName: string): FilterState | undefined {
        return this.filterStates.find(state => state.name === colName);
    }

    onBooleanFilterChanged(colName: string, event: Event): void {
        const target = event.target as HTMLInputElement;
        this.onFilterChanged(colName, target.checked);
    }

    onTextFilterChanged(colName: string, event: Event): void {
        const target = event.target as HTMLInputElement;
        const filterState = this.findFilterState(colName);
        if (filterState) {
            this.textInputSubject.next({
                name: colName,
                value: target.value,
                field: filterState.field,
                subResource: filterState.subResource
            });
        }
    }

    private updateTextFilter(field: string, value: string, subResource?: string): void {
        const filterState = this.findFilterState(field);
        if (filterState && filterState.type === FilterBarComponent.FILTER_TYPE_TEXT) {
            filterState.value = value;
            this.emitActiveFilters();
        }
    }

    onDateFilterChanged(colName: string, dateType: 'start' | 'end', event: Event): void {
        const target = event.target as HTMLInputElement;
        const filterState = this.findFilterState(colName);
        if (filterState && filterState.type === FilterBarComponent.FILTER_TYPE_DATE) {
            filterState.value = { ...filterState.value, [dateType]: target.value };
            this.emitActiveFilters();
        }
    }

    onNumberFilterChanged(colName: string, boundType: 'min' | 'max', event: Event): void {
        const target = event.target as HTMLInputElement;
        const numValue = target.value === '' ? null : Number(target.value);
        const filterState = this.findFilterState(colName);
        if (filterState) {
            this.numberInputSubject.next({
                name: colName,
                boundType: boundType,
                value: numValue,
                field: filterState.field,
                subResource: filterState.subResource
            });
        }
    }

    onCheckboxesFilterChanged(colName: string, option: string, event: Event): void {
        const target = event.target as HTMLInputElement;
        const filterState = this.findFilterState(colName);
        if (filterState && filterState.type === FilterBarComponent.FILTER_TYPE_CHECKBOXES) {
            filterState.value[option] = target.checked;
            this.emitActiveFilters();
        }
    }

    private updateNumberFilter(colName: string, boundType: 'min' | 'max', value: number | null): void {
        const filterState = this.findFilterState(colName);
        if (filterState && filterState.type === FilterBarComponent.FILTER_TYPE_NUMBER) {
            filterState.value = { ...filterState.value, [boundType]: value };
            this.emitActiveFilters();
        }
    }

    onFilterChanged(colName: string, value: any): void {
        const filterState = this.findFilterState(colName);
        if (filterState) {
            filterState.value = value;
            this.emitActiveFilters();
        }
    }

    onFilterActiveChanged(colName: string, event: Event): void {
        const target = event.target as HTMLInputElement;
        const filterState = this.findFilterState(colName);
        if (filterState) {
            filterState.active = target.checked;
            if (filterState.type === FilterBarComponent.FILTER_TYPE_CHECKBOXES) {
                if (!filterState.active) {
                    for (const option in filterState.value) {
                        filterState.value[option] = false;
                    }
                }
            }
            this.emitActiveFilters();
        }
    }

    resetAllFilters(): void {
        this.filterStates.forEach(state => {
            state.active = false;
            state.value = this.getInitialValueForType(state.type);
        });
        this.emitActiveFilters();
    }

    private getActiveFilters(): Record<string, any> {
        const activeFilters: Record<string, any> = {};
        this.filterStates
            .filter(state => state.active)
            .forEach(state => {
                if (state.subResource) {
                    if (!activeFilters[state.subResource]) {
                        activeFilters[state.subResource] = {};
                    }
                    this.setFilterValue(activeFilters[state.subResource], state);
                } else {
                    this.setFilterValue(activeFilters, state);
                }
            });
        return activeFilters;
    }

    private emitActiveFilters(): void {
        const activeFilters: Record<string, any> = this.getActiveFilters();
        const activeCount = this.countActiveFilters();
        this.filterChanged.emit({ filters: activeFilters, activeCount });
    }

    private setFilterValue(obj: Record<string, any>, state: FilterState): void {
        if (state.type === FilterBarComponent.FILTER_TYPE_BOOLEAN) {
            obj[state.field] = state.value;
        } else if (state.type === FilterBarComponent.FILTER_TYPE_TEXT) {
            obj[state.field] = state.value;
        } else if (state.type === FilterBarComponent.FILTER_TYPE_DATE) {
            if (state.value.start !== null || state.value.end !== null) {
                obj[state.field] = state.value;
            } else {
                obj[state.field] = {};
            }
        } else if (state.type === FilterBarComponent.FILTER_TYPE_NUMBER) {
            if (state.value.min !== null || state.value.max !== null) {
                obj[state.field] = state.value;
            } else {
                obj[state.field] = {};
            }
        } else if (state.type === FilterBarComponent.FILTER_TYPE_CHECKBOXES) {
            // Add this block to handle checkbox filters
            const selectedOptions = Object.entries(state.value)
                .filter(([_, isChecked]) => isChecked)
                .map(([option, _]) => option);
            if (selectedOptions.length > 0) {
                obj[state.field] = selectedOptions;
            }
        }
    }

    saveFilterConfig(): void {
        this.filterSave.emit();
    }

    getColumnText(colName: string): string {
        const column = this.listColDefinitions.find(col => col.name === colName);
        return column ? column.text : '';
    }

    get FILTER_TYPE_BOOLEAN(): string {
        return FilterBarComponent.FILTER_TYPE_BOOLEAN;
    }

    get FILTER_TYPE_TEXT(): string {
        return FilterBarComponent.FILTER_TYPE_TEXT;
    }

    get FILTER_TYPE_DATE(): string {
        return FilterBarComponent.FILTER_TYPE_DATE;
    }

    get FILTER_TYPE_NUMBER(): string {
        return FilterBarComponent.FILTER_TYPE_NUMBER;
    }

    get FILTER_TYPE_CHECKBOXES(): string {
        return FilterBarComponent.FILTER_TYPE_CHECKBOXES;
    }
}