import {
    AfterViewInit,
    ChangeDetectorRef,
    Component,
    EventEmitter,
    Input,
    OnInit,
    Output,
    ViewChild
} from '@angular/core';
import {MatPaginator, MatPaginatorIntl, PageEvent} from "@angular/material/paginator";
import {FormBuilder, FormGroup} from "@angular/forms";
import {debounceTime, distinctUntilChanged} from "rxjs";

@Component({
    selector: 'app-paging',
    templateUrl: './paging.component.html',
    styleUrl: './paging.component.scss'
})
export class PagingComponent implements OnInit, AfterViewInit {

    @Input() public dataSource!: any;
    @Input() public getDataFunction!: Function;
    @Input() public pageSize!: number;
    @Input() public pageSizeOptions!: number[];
    @Input() public searchable: boolean;
    @Input() public hidePageSize: boolean;
    @Input() public displayOptions!: { [key: string]: any };
    @Input() public defaultDisplayOption!: string;
    @Input() public showCreateDataButton: boolean;
    @Output() public displayOptionChange = new EventEmitter<string>();
    @Output() public createNewData = new EventEmitter();

    @ViewChild(MatPaginator) public paginator!: MatPaginator;

    protected defaultPageSize: number = 50;
    protected defaultPageSizeOptions: number[] = [20, 50, 100];

    protected dataLength: number;
    protected pageEvent: PageEvent;
    protected pageIndex: number;
    protected searchForm!: FormGroup;
    protected dataInitialized: boolean = false;
    protected selectedDisplayOption: string = '';
    protected displayOptionKeys: string[] = [];

    constructor(
        private fb: FormBuilder
    ) {
        this.dataLength = 0;
        this.pageEvent = new PageEvent();
        this.pageIndex = 0;
        this.searchable = false;
        this.hidePageSize = false;
        this.showCreateDataButton = false;
    }

    ngOnInit() {
        this.pageSize = this.pageSize !== undefined ? this.pageSize : this.defaultPageSize;
        this.pageSizeOptions = this.pageSizeOptions !== undefined ? this.pageSizeOptions : this.defaultPageSizeOptions;
        this.paginator = new MatPaginator(new MatPaginatorIntl(), ChangeDetectorRef.prototype);

        if (this.searchable) {
            this.searchForm = this.fb.group({
                inputText: ['']
            });
            this.searchForm.get('inputText')?.valueChanges.pipe(
                debounceTime(1000),
                distinctUntilChanged()
            ).subscribe(value => {
                this.resetPageIndex();
                this.getData();
            });
        }
        if (this.displayOptions !== undefined) {
            this.displayOptionKeys = Object.keys(this.displayOptions);
            this.selectedDisplayOption = this.defaultDisplayOption || Object.keys(this.displayOptions)[0] || '';
        }

    }

    ngAfterViewInit() {

    }

    getData() {
        this.getDataFunction(
            this.getPageIndex(),
            this.getPageSize(),
            this.searchForm ? this.searchForm.get('inputText')?.value : undefined
        );
    }

    onCreateData() {
        this.createNewData.emit();
    }

    handlePageEvent(e: PageEvent) {
        this.pageEvent = e;
        this.dataLength = e.length;
        this.pageIndex = e.pageIndex.valueOf();
        this.pageSize = e.pageSize.valueOf();
        this.getData();
    }

    resetPageIndex(): void {
        this.pageIndex = 0;
    }

    getPageIndex(): number {
        return this.pageIndex + 1;
    }

    getPageSize(): number {
        return this.pageSize;
    }

    setDataLength(dataLength: number): void {
        this.dataInitialized = true;
        this.dataLength = dataLength;
    }

    clearForm() {
        this.searchForm.get('inputText')!.setValue('');
    }

    getSearchValue() {
        if (this.searchable) {
            return this.searchForm.get('inputText')!.value;
        }
        return undefined;
    }

    onDisplayOptionChange(event: Event): void {
        this.displayOptionChange.emit(String(event));
    }

    protected readonly Object = Object;
}
