import {
    Component,
    forwardRef,
    Inject,
    Input,
    OnDestroy,
    OnInit,
    Renderer2,
    ViewChild,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { getWeek, isValidWeek } from '@utils/week';
import { APP_SETTINGS, LocalizationService } from '@shared/services';
import { TranslateService } from '@ngx-translate/core';
import { DATE_FORMAT } from '@shared/helpers';
import { AppSettings } from '@shared/models-legacy';

import * as moment from 'moment';
import { Calendar } from 'primeng/calendar';
import { parseUserInputDate } from './calendar-input.methods';
import { timer, interval, Subscription } from 'rxjs';

@Component({
    selector: 'calendar-input-week',
    templateUrl: 'calendar-input-week.component.html',
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => CalendarInputWeekComponent), // replace name as appropriate
            multi: true,
        },
    ],
})
export class CalendarInputWeekComponent
    implements OnInit, ControlValueAccessor, OnDestroy
{
    @ViewChild('calendar')
    calendar: Calendar;

    timer: Subscription; 
    interval: Subscription;

    @ViewChild('calendar_input_field')
    calendarInput: any;

    value: [Date, Date];

    writeValue(value: [Date, Date]) {
        let [from] = value || []; // empty value validation

        if (!moment(from).isValid) from = new Date(); // fallback to today

        value = from ? getWeek(from) : null; // working only with weeks

        this.value = value;
        this.updateStr();
    }

    onTouched = () => {};
    onChanged = (_: [Date, Date]) => {};

    registerOnChange(fn: (value: Date[]) => void) {
        this.onChanged = fn;
    }

    registerOnTouched(fn: () => void) {
        this.onTouched = fn;
    }

    @Input() disabledDates: Date[];

    @Input() error: string;

    dateStr: string;

    currentWeek: string;
    @Input() label: string;

    @Input() minDate: Date;

    @Input() maxDate: Date;

    placeholder = 'SHARED.DATE_FORMAT_WEEK';
    translatedPlaceholder: string;

    translatedDateFormat: string;

    @Input() readonly = false;

    months: MonthName[] = [];
    days: DayName[] = [];

    constructor(
        private translate: TranslateService,
        public localizationService: LocalizationService,
        private renderer: Renderer2,
        @Inject(APP_SETTINGS) public settings: AppSettings,
    ) {
        this.translate
            .get([
                'OF-MONTH.1',
                'OF-MONTH.2',
                'OF-MONTH.3',
                'OF-MONTH.4',
                'OF-MONTH.5',
                'OF-MONTH.6',
                'OF-MONTH.7',
                'OF-MONTH.8',
                'OF-MONTH.9',
                'OF-MONTH.10',
                'OF-MONTH.11',
                'OF-MONTH.12',
                'DAYS-SHORT.0',
                'DAYS-SHORT.1',
                'DAYS-SHORT.2',
                'DAYS-SHORT.3',
                'DAYS-SHORT.4',
                'DAYS-SHORT.5',
                'DAYS-SHORT.6',
            ])
            .toPromise()
            .then((values) => {
                this.months = [
                    { month: 0, name: values['OF-MONTH.1'] },
                    { month: 1, name: values['OF-MONTH.2'] },
                    { month: 2, name: values['OF-MONTH.3'] },
                    { month: 3, name: values['OF-MONTH.4'] },
                    { month: 4, name: values['OF-MONTH.5'] },
                    { month: 5, name: values['OF-MONTH.6'] },
                    { month: 6, name: values['OF-MONTH.7'] },
                    { month: 7, name: values['OF-MONTH.8'] },
                    { month: 8, name: values['OF-MONTH.9'] },
                    { month: 9, name: values['OF-MONTH.10'] },
                    { month: 10, name: values['OF-MONTH.11'] },
                    { month: 11, name: values['OF-MONTH.12'] },
                ];

                this.days = [
                    { day: 0, name: values['DAYS-SHORT.0'] },
                    { day: 1, name: values['DAYS-SHORT.1'] },
                    { day: 2, name: values['DAYS-SHORT.2'] },
                    { day: 3, name: values['DAYS-SHORT.3'] },
                    { day: 4, name: values['DAYS-SHORT.4'] },
                    { day: 5, name: values['DAYS-SHORT.5'] },
                    { day: 6, name: values['DAYS-SHORT.6'] },
                ];
            });
    }

    ngOnInit() {
        //this.settings.startValidationDatesUpdatingInterval();

        this.translate
            .get('SHARED.DATE_FORMAT')
            .toPromise()
            .then((x) => {
                this.translatedDateFormat = x;
            });

        this.translate
            .get(this.placeholder)
            .toPromise()
            .then((x) => {
                this.translatedPlaceholder = x;
            });

        this.translate
            .get('SHARED.CURRENT_WEEK')
            .toPromise()
            .then((x) => {
                this.currentWeek = x;
            });

        if (this.readonly && this.calendarInput)
            this.renderer.setAttribute(
                this.calendarInput.nativeElement,
                'readonly',
                'readonly',
            );

        
        this.minDate = new Date(this.minDate);
        this.maxDate = new Date(this.maxDate);
        var dateNow = new Date();
        var dateTomorrow = new Date();
        dateTomorrow.setHours(0,0,0,0);
        dateTomorrow.setDate(dateTomorrow.getDate() + 1);
        var durationDelay = dateTomorrow.getTime()-dateNow.getTime();
        this.timer = timer(durationDelay).subscribe(() => 
        {
            this.minDate.setDate(this.minDate.getDate()+1);
            this.maxDate.setDate(this.maxDate.getDate()+1);
        });
        this.interval = interval(1000*60*60*24).subscribe();
    }

    ngOnDestroy() {
        //this.settings.stopValidationDatesUpdatingInterval();
        this.timer.unsubscribe();
        this.interval.unsubscribe();

    }

    openCalendar(event: any) {
        this.calendar.showOverlay();
        this.calendar.cd.detectChanges();
        event.stopPropagation();
    }

    inputKeyup() {
        this.manualInputHandler();
    }

    manualInputHandler() {
        const value = this.dateStr;
        if (!value) return;

        const [from, to] = value
            .split('-')
            .map((v) => v.trim())
            .map((v) => parseUserInputDate(v, DATE_FORMAT));

        if (!from || !to) return;

        this.onSelect(from);
    }

    onModelChange() {
        const [from, to] = this.value;
        if (from && to) this.calendar.hideOverlay();
        this.updateStr();
        this.onChanged(this.value);
    }

    onSelect(value: Date) {
        this.error = null;
        this.value = getWeek(value);
        this.onModelChange();
    }

    clearInput() {
        this.dateStr = '';
        this.value = null;
        this.onChanged(this.value);
    }

    private getDateString(): string {
        const { value } = this;

        if (!isValidWeek(value)) {
            return this.translatedPlaceholder;
        }

        const [from, to] = value.map((d) => moment(d));

        const today = moment().startOf('day');
        if (moment(from) <= today && moment(today) <= to) {
            return this.currentWeek;
        }

        return `${this.format(from)} - ${this.format(to)}`;
    }

    private format(m: moment.Moment) {
        return m?.isValid() ? m.format(DATE_FORMAT) : this.translatedDateFormat;
    }

    updateStr() {
        this.dateStr = this.getDateString();
    }
}

export interface MonthName {
    month?;
    name?;
}

export interface DayName {
    day?;
    name?;
}
