import { DateComputation } from './date-computation';
import { DatePreFilter, FilterDatePreset } from './../../../model/common-model';
import moment from 'moment';
import { IRangePreset } from '../../../ui/calendar/calendar-utils';
import { observable } from 'aurelia-binding';
import { Container, TaskQueue } from 'aurelia-framework';
import { I18N } from 'aurelia-i18n';


export class DateFilterHelper {
    private taskQueue: TaskQueue;
    private i18n: I18N;
    private dateComputation: DateComputation;
    private dateFormat: string = "DD/MM/YYYY";
    private _filterProperties = ['fromDate', 'toDate', 'selectedDatePreFilter', 'isDateNullable', 'isLastMonth', 'isLastWeek',
        'isThisWeek', 'isThisMonth', 'isNextWeek', 'isNextMonth'];

    private propertyChangedHelper: (newVal: Date | boolean | number, oldVal: Date | boolean | number) => void;
    private resetFilterCallback: () => {};

    @observable
    public fromDate: Date;
    @observable
    public toDate: Date;
    @observable
    public selectedDatePreFilter: number;
    @observable
    public isDateNullable: boolean;

    @observable
    public isLastMonth: boolean;
    @observable
    public isLastWeek: boolean;
    @observable
    public isThisWeek: boolean;
    @observable
    public isThisMonth: boolean;
    @observable
    public isNextWeek: boolean;
    @observable
    public isNextMonth: boolean;
    @observable
    public viewToday: boolean;
    @observable
    public includeToday: boolean = false;

    public preset: Array<IRangePreset>;

    @observable
    public selectedPreset: IRangePreset;
    public ignorePropertyChanges = false;

    constructor(propertyChangedHelper, resetFilterCallback?) {
        this.dateComputation = Container.instance.get(DateComputation);

        this.taskQueue = Container.instance.get(TaskQueue);
        this.i18n = Container.instance.get(I18N);
        this.initPreset();
        this.propertyChangedHelper = propertyChangedHelper;
        this.resetFilterCallback = resetFilterCallback;
    }

    private initPreset() {
        let today = moment();
        this.preset = [
            {
                label: "common:grid.past",
                preset: [
                    Date.MIN_DATE,
                    moment(today).subtract(1, "day").toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = true;
                    this.selectedDatePreFilter = DatePreFilter.Past;
                    if (this.includeToday) {
                        this.toDate = today.toDate();
                    }
                }
            } as IRangePreset,
            {
                label: "common:grid.today",
                preset: [
                    moment(today).toDate(),
                    moment(today).toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = false;
                    this.selectedDatePreFilter = DatePreFilter.Today;
                }
            } as IRangePreset,
            {
                label: "common:grid.futur",
                preset: [
                    moment(today).add(1, "day").toDate(),
                    Date.MAX_DATE
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = true;
                    this.selectedDatePreFilter = DatePreFilter.Futur;
                    if (this.includeToday) {
                        this.fromDate = today.toDate();
                    }
                }
            } as IRangePreset,

            {
                label: "common:grid.lastMonth",
                preset: [
                    moment(today).subtract(1, "month").startOf("month").toDate(),
                    moment(today).subtract(1, "month").endOf("month").toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = false;
                    this.isLastMonth = true;
                }
            } as IRangePreset,
            {
                label: "common:grid.lastWeek",
                preset: [
                    moment(today).subtract(1, "week").startOf("week").toDate(),
                    moment(today).subtract(1, "week").endOf("week").toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = false;
                    this.isLastWeek = true;
                }
            } as IRangePreset,
            {
                label: "common:grid.thisWeek",
                preset: [
                    moment(today).startOf("week").toDate(),
                    moment(today).endOf("week").toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = false;
                    this.isThisWeek = true;
                },
                includeCurrentDate: true
            } as IRangePreset,
            {
                label: "common:grid.thisMonth",
                preset: [
                    moment(today).startOf("month").toDate(),
                    moment(today).endOf("month").toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = false;
                    this.isThisMonth = true;
                },
                includeCurrentDate: true
            } as IRangePreset,

            {
                label: "common:grid.nextWeek",
                preset: [
                    moment(today).add(1, "week").startOf("week").toDate(),
                    moment(today).add(1, "week").endOf("week").toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = false;
                    this.isNextWeek = true;
                }
            } as IRangePreset,
            {
                label: "common:grid.nextMonth",
                preset: [
                    moment(today).add(1, "month").startOf("month").toDate(),
                    moment(today).add(1, "month").endOf("month").toDate()
                ],
                action: () => {
                    this.resetSelection();
                    this.viewToday = false;
                    this.isNextMonth = true;
                }
            } as IRangePreset
        ]
    }

    public getPreset(): Array<IRangePreset> {
        return this.preset;
    }

    public getModelFilter(): any {
        return {
            filterType: 'date', type: 'greaterThan', dateFrom: this.fromDate, dateTo: this.toDate, datePreFilter: this.selectedDatePreFilter, isDateNullable: this.isDateNullable,
            isLastMonth: this.isLastMonth, isLastWeek: this.isLastWeek, isThisWeek: this.isThisWeek, isThisMonth: this.isThisMonth, isNextWeek: this.isNextWeek, isNextMonth: this.isNextMonth
        };
    }

    public getModel(type: 'inRange' | 'greaterThan' = 'inRange'): any {
        return this.isFilterActive() ? {
            filterType: 'date', type: type, dateFrom: this.fromDate, dateTo: this.toDate, datePreFilter: this.selectedDatePreFilter, isDateNullable: this.isDateNullable, includeToday: this.includeToday,
            isLastMonth: this.isLastMonth, isLastWeek: this.isLastWeek, isThisWeek: this.isThisWeek, isThisMonth: this.isThisMonth, isNextWeek: this.isNextWeek, isNextMonth: this.isNextMonth
        } : null;
    }

    public isFilterActive(): boolean {
        return (this.fromDate != null || this.toDate != null || this.selectedDatePreFilter != null || this.isDateNullable ||
            this.isLastMonth || this.isLastWeek || this.isThisWeek || this.isThisMonth || this.isNextWeek || this.isNextMonth);
    }

    public getFilter(): string {
        if (this.selectedDatePreFilter == DatePreFilter.Past) {
            this.selectedPreset = this.preset[FilterDatePreset.Past];
            this.viewToday = true;
            if (this.includeToday) {
                this.toDate = moment().toDate();
            }
        } else if (this.selectedDatePreFilter == DatePreFilter.Today) {
            this.selectedPreset = this.preset[FilterDatePreset.Today];
        } else if (this.selectedDatePreFilter == DatePreFilter.Futur) {
            this.selectedPreset = this.preset[FilterDatePreset.Futur];
            this.viewToday = true;
            if (this.includeToday) {
                this.fromDate = moment().toDate();
            }
        }

        if (this.isLastMonth) {
            this.selectedPreset = this.preset[FilterDatePreset.IsLastMonth];
        } else if (this.isLastWeek) {
            this.selectedPreset = this.preset[FilterDatePreset.IsLastWeek];
        } else if (this.isThisWeek) {
            this.selectedPreset = this.preset[FilterDatePreset.IsThisWeek];
        } else if (this.isThisMonth) {
            this.selectedPreset = this.preset[FilterDatePreset.IsThisMonth];
        } else if (this.isNextWeek) {
            this.selectedPreset = this.preset[FilterDatePreset.IsNextWeek];
        } else if (this.isNextMonth) {
            this.selectedPreset = this.preset[FilterDatePreset.IsNextMonth];
        }
        return `
        <div class="col s12 m12 l12 date-filter">
            <ui-field label.bind="params.colDef.headerName">
                <ui-range-picker clear="true" date-from.bind="filterHelper.fromDate" date-to.bind="filterHelper.toDate"
                presets.bind="filterHelper.preset" selected-preset.bind="filterHelper.selectedPreset" autoset-when-opened.one-time='false'>
                    <div slot="range-footer" class="range-footer">
                        <div>
                            <ui-checkbox show.bind="filterHelper.viewToday" checked.bind="filterHelper.includeToday">
                                <span t="common:grid.includeToday"></span>
                            </ui-checkbox>
                        </div>
                        <ui-checkbox checked.bind="filterHelper.isDateNullable">
                            <span t="grid.isDateNullable"></span>
                        </ui-checkbox>
                        <ui-button class="date-filter-reset" t="[label]common:grid.resetFilter" click.delegate="filterHelper.resetFilter()" icon="digi-cross-circle"></ui-button>
                    </div>
                </ui-range-picker>
            </ui-field>
        </div>`;
    }

    public getValue(): string {
        let dateInterval = this.dateComputation.GetDateIntervalFromFilter(this.getModel());
        if (dateInterval.dateFrom != null || dateInterval.dateTo != null) {
            if (dateInterval.dateTo == null) {
                return '>= ' + moment(dateInterval.dateFrom).format(this.dateFormat);
            }
            else if (dateInterval.dateFrom == null) {
                return '<= ' + moment(dateInterval.dateTo).format(this.dateFormat);
            }
            else {
                return moment(dateInterval.dateFrom).format(this.dateFormat) + ' - ' + moment(dateInterval.dateTo).format(this.dateFormat);
            }
        }
        return null;
    }

    public getModelAsString(): string {
        return this.getValue() ?? this.i18n.tr('grid.noFilter', { ns: "common" });
    }

    private resetSelection() {
        this.selectedDatePreFilter = null;
        this.isLastMonth = false;
        this.isLastWeek = false;
        this.isThisMonth = false;
        this.isThisWeek = false;
        this.isNextMonth = false;
        this.isNextWeek = false;
    }

    public resetFilter() {
        let resetModel = {
            fromDate: null,
            toDate: null,
            selectedDatePreFilter: null,
            isDateNullable: false,
            isLastMonth: false,
            isLastWeek: false,
            isThisWeek: false,
            isThisMonth: false,
            isNextWeek: false,
            isNextMonth: false,
        };
        this.selectedPreset = null;
        this.includeToday = null;

        if (this.isAnyDifferent(this, resetModel)) {
            this.ignorePropertyChanges = true;

            this.assignToThis(resetModel);

            if (this.resetFilterCallback) {
                this.resetFilterCallback();
            }

            this.taskQueue.queueMicroTask(() => this.ignorePropertyChanges = false);
        }
    }

    public isAnyDifferent(current: any, next: any): boolean {
        return this._filterProperties.some(p => current[p] !== next[p]);
    }

    public assignToThis(next: any) {
        this._filterProperties.forEach(p => this[p] = next[p]);
    }

    //#region Observers
    private viewTodayChanged(newValue, oldValue) {
        if (newValue != oldValue) {
            if (!newValue) {
                this.includeToday = false;
            }
        }
    }

    private includeTodayChanged(newValue, oldValue) {
        if (newValue != oldValue) {
            if (newValue) {
                if (this.selectedDatePreFilter == DatePreFilter.Past) {
                    this.toDate = moment().toDate();
                } else if (this.selectedDatePreFilter == DatePreFilter.Futur) {
                    this.fromDate = moment().toDate();
                }
            } else {
                if (this.selectedDatePreFilter == DatePreFilter.Past) {
                    this.toDate = this.preset[FilterDatePreset.Past].preset[FilterDatePreset.Today];
                } else if (this.selectedDatePreFilter == DatePreFilter.Futur) {
                    this.fromDate = this.preset[FilterDatePreset.Futur].preset[FilterDatePreset.Past];
                }
            }
        }
    }

    private fromDateChanged(newVal: Date, oldVal: Date) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private toDateChanged(newVal: Date, oldVal: Date) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private isDateNullableChanged(newVal: boolean, oldVal: boolean) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private isLastMonthChanged(newVal: boolean, oldVal: boolean) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private isLastWeekChanged(newVal: boolean, oldVal: boolean) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private isThisMonthChanged(newVal: boolean, oldVal: boolean) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private isThisWeekChanged(newVal: boolean, oldVal: boolean) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private isNextMonthChanged(newVal: boolean, oldVal: boolean) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private isNextWeekChanged(newVal: boolean, oldVal: boolean) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private selectedDatePreFilterChanged(newVal: number, oldVal: number) {
        this.propertyChangedHelper(newVal, oldVal);
    }

    private selectedPresetChanged(newVal: number, oldVal: number) {
        if (newVal == null) {
            this.resetSelection();
        }
    }
    //#endregion
}