import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss';

class Controller extends Section {
    constructor($element, $) {
        super($element, $);
        this.date = new Date();
        this.events = {};
        this.buildYearFilter();
    }

    get year() {
        return this.date.getFullYear();
    }

    set year(value) {
        const newYear = new Date();
        newYear.setFullYear(value);

        this.date = newYear;

        this.refresh()
            .then(() => this.repaint())
            .then(() => this.getContractHolidays())
            .then(() => this.getYearHolidays());
    }

    get businessId() {
        return this._businessId;
    }

    set businessId(value) {
        this._businessId = value;
        if (value) {
            this.refresh()
                .then(() => this.repaint())
                .then(() => this.getContractHolidays())
                .then(() => this.getYearHolidays());
        }
    }

    get date() {
        return this._date;
    }

    set date(value) {
        this._date = value;
        value.setHours(0, 0, 0, 0);

        this.months = new Array(12);

        for (let i = 0; i < this.months.length; i++) {
            const now = new Date(value.getTime());
            now.setDate(1);
            now.setMonth(i);
            this.months[i] = now;
        }
    }

    get worker() {
        return this._worker;
    }

    set worker(value) {
        this._worker = value;

        if (value) {
            this.getIsSubordinate();
            this.getActiveContract();
        }
    }

    get payedHolidays() {
        return this._businessId;
    }

    buildYearFilter() {
        const now = new Date();
        now.setFullYear(now.getFullYear() + 1);

        const maxYear = now.getFullYear();
        const minRange = maxYear - 5;

        const years = [];
        for (let i = maxYear; i > minRange; i--)
            years.push({year: i});

        this.yearFilter = years;
    }

    getIsSubordinate() {
        this.$http.get(`Workers/${this.worker.id}/isSubordinate`)
            .then(res => this.isSubordinate = res.data);
    }

    getActiveContract() {
        this.$http.get(`Workers/${this.worker.id}/activeContract`).then(res => {
            if (res.data)
                this.businessId = res.data.businessFk;
        });
    }

    getContractHolidays() {
        this.getHolidays({
            businessFk: this.businessId,
            year: this.year
        }, data => this.contractHolidays = data);
    }

    getYearHolidays() {
        this.getHolidays({
            year: this.year
        }, data => this.yearHolidays = data);
    }

    getHolidays(params, cb) {
        this.$http.get(`Workers/${this.worker.id}/holidays`, {params})
            .then(res => cb(res.data));
    }

    onData(data) {
        this.events = {};
        this.calendar = data.calendar;

        let addEvent = (day, newEvent) => {
            const timestamp = new Date(day).getTime();
            const event = this.events[timestamp];

            if (event) {
                const oldName = event.name;
                Object.assign(event, newEvent);
                event.name = `${oldName}, ${event.name}`;
            } else
                this.events[timestamp] = newEvent;
        };

        if (data.holidays) {
            data.holidays.forEach(holiday => {
                const holidayDetail = holiday.detail && holiday.detail.name;
                const holidayType = holiday.type && holiday.type.name;
                const holidayName = holidayDetail || holidayType;

                addEvent(holiday.dated, {
                    name: holidayName,
                    className: 'festive'
                });
            });
        }
        if (data.absences) {
            data.absences.forEach(absence => {
                let type = absence.absenceType;
                addEvent(absence.dated, {
                    name: type.name,
                    color: type.rgb,
                    type: type.code,
                    absenceId: absence.id
                });
            });
        }
    }

    repaint() {
        let calendars = this.element.querySelectorAll('vn-calendar');
        for (let calendar of calendars)
            calendar.$ctrl.repaint();
    }

    formatDay(day, element) {
        let event = this.events[day.getTime()];
        if (!event) return;

        let dayNumber = element.firstElementChild;
        dayNumber.title = event.name;
        dayNumber.style.backgroundColor = event.color;

        if (event.border)
            dayNumber.style.border = event.border;

        if (event.className)
            dayNumber.classList.add(event.className);
    }

    pick(absenceType) {
        if (!this.isSubordinate) return;
        if (absenceType == this.absenceType)
            absenceType = null;

        this.absenceType = absenceType;
    }

    onSelection($event, $days) {
        if (!this.absenceType)
            return this.vnApp.showMessage(this.$t('Choose an absence type from the right menu'));

        const day = $days[0];
        const stamp = day.getTime();
        const event = this.events[stamp];
        const calendar = $event.target.closest('vn-calendar').$ctrl;

        if (event && event.absenceId) {
            if (event.type == this.absenceType.code)
                this.delete(calendar, day, event);
            else
                this.edit(calendar, event);
        } else
            this.create(calendar, day);
    }

    create(calendar, dated) {
        const absenceType = this.absenceType;
        const params = {
            dated: dated,
            absenceTypeId: absenceType.id,
            businessFk: this.businessId
        };

        const path = `Workers/${this.$params.id}/createAbsence`;
        this.$http.post(path, params).then(res => {
            const newEvent = res.data;
            this.events[dated.getTime()] = {
                name: absenceType.name,
                color: absenceType.rgb,
                type: absenceType.code,
                absenceId: newEvent.id
            };

            this.repaintCanceller(() =>
                this.refresh()
                    .then(calendar.repaint())
                    .then(() => this.getContractHolidays())
                    .then(() => this.getYearHolidays())
                    .then(() => this.repaint())
            );
        });
    }

    edit(calendar, event) {
        const absenceType = this.absenceType;
        const params = {
            absenceId: event.absenceId,
            absenceTypeId: absenceType.id
        };
        const path = `Workers/${this.$params.id}/updateAbsence`;
        this.$http.patch(path, params).then(() => {
            event.color = absenceType.rgb;
            event.name = absenceType.name;
            event.type = absenceType.code;

            this.repaintCanceller(() =>
                this.refresh()
                    .then(calendar.repaint())
                    .then(() => this.getContractHolidays())
                    .then(() => this.getYearHolidays())
            );
        });
    }

    delete(calendar, day, event) {
        const params = {absenceId: event.absenceId};
        const path = `Workers/${this.$params.id}/deleteAbsence`;
        this.$http.delete(path, {params}).then(() => {
            delete this.events[day.getTime()];

            this.repaintCanceller(() =>
                this.refresh()
                    .then(calendar.repaint())
                    .then(() => this.getContractHolidays())
                    .then(() => this.getYearHolidays())
                    .then(() => this.repaint())
            );
        });
    }

    repaintCanceller(cb) {
        if (this.canceller) {
            clearTimeout(this.canceller);
            this.canceller = null;
        }

        this.canceller = setTimeout(
            () => cb(), 500);
    }

    refresh() {
        const params = {
            workerFk: this.$params.id,
            businessFk: this.businessId,
            year: this.year
        };
        return this.$http.get(`Calendars/absences`, {params})
            .then(res => this.onData(res.data));
    }
}

ngModule.vnComponent('vnWorkerCalendar', {
    template: require('./index.html'),
    controller: Controller,
    bindings: {
        worker: '<'
    }
});