import {
    Component,
    EventEmitter,
    Input,
    OnChanges,
    OnInit,
    Output,
    SimpleChanges,
} from '@angular/core';
import { IDateTab } from '@toolkit/date-tabs/date-tabs.component';
import { areSame, isSameOrBefore } from '@utils/date';
import { DatesTranslationService } from '@shared/services/dates-translation.service';

@Component({
    selector: 'date-selector-base',
    template: '',
})
export abstract class DateSelectorBaseComponent<T = unknown>
    implements OnInit, OnChanges
{
    @Input() caption!: string;
    @Input() selectedDate!: Date;
    @Input() dateFrom!: Date;
    @Input() dateTo!: Date;
    @Input() minDate: Date;
    @Input() maxDate: Date;
    @Input() tabsPerPage = 7;

    @Output() tabClick = new EventEmitter<T>();

    tabs: IDateTab<T>[] = [];

    protected constructor(
        protected translationService: DatesTranslationService,
    ) {}

    ngOnInit() {
        this.translationService.init().then(() => {
            this.tabs = this.generateTabs();
        });
    }

    ngOnChanges(changes: SimpleChanges) {
        this.updateTabs();
    }

    public onTabClick(value: T) {
        this.tabClick.emit(value);
    }

    protected isActive(date: Date) {
        if (!this.selectedDate || !date) {
            return false;
        }

        return areSame(this.selectedDate, date);
    }

    protected generateTabs(): IDateTab<T>[] {
        const tabs = [];
        let date = this.computeFirstDate();

        // eslint-disable-next-line no-constant-condition
        while (true) {
            const tab = this.generateTab(date);

            tabs.push(tab);
            date = this.computeNextDate(date);

            // generate tabs until we reach this.dateTo and
            // can fulfill integer number of pages
            if (
                !isSameOrBefore(date, this.dateTo) &&
                tabs.length % this.tabsPerPage === 0
            ) {
                break;
            }
        }

        return tabs;
    }

    protected abstract updateTabs();
    protected abstract generateTab(date: Date): IDateTab<T>;
    protected abstract computeNextDate(date: Date): Date;
    protected abstract computeFirstDate(): Date;
}
