<template>
    <form :action="storeUrl" method="post" class="default" :data-dialog="asDialog ? '' : null" @submit="validateInputs">
        <input type="hidden" :name="csrf.name" :value="csrf.value">
        <input v-for="id in responsibleGroups" type="hidden" name="responsibilities[statusgroup][]" :value="id" :key="`group-${id}`">
        <input v-for="id in responsibleInstitutes" type="hidden" name="responsibilities[institute][]" :value="id" :key="`institute-${id}`">
        <input v-for="id in responsibleUsers" type="hidden" name="responsibilities[user][]" :value="id" :key="`user-${id}`">

        <StudipMessageBox type="info" v-if="errors.length > 0">
            {{ $gettext('Folgende Angaben müssen korrigiert werden, um das Formular abschicken zu können:') }}

            <template #details>
                <ul>
                    <li v-for="(error, index) in errors" :key="`error-${index}`">
                        {{ error }}
                    </li>
                </ul>
            </template>
        </StudipMessageBox>

        <fieldset>
            <legend>{{ $gettext('Ort und Zeit') }}</legend>

            <label>
                <span class="required">{{ $gettext('Ort') }}</span>

                <input required type="text" name="room"
                       v-model.trim="room"
                       :placeholder="$gettext('Ort')">
            </label>

            <label :class="{'col-3': !isSingleDay}">
                <span class="required">{{ $gettext('Intervall') }}</span>
                <select required name="interval" v-model.number="interval">
                    <option v-for="item in intervals" :key="item.key" :value="item.key">
                        {{ item.label }}
                    </option>
                </select>
            </label>

            <label class="col-3" v-if="!isSingleDay">
                <span class="required">{{ $gettext('Am Wochentag') }}</span>

                <select required name="day-of-week" @change="evt => dayOfWeek = parseInt(evt.target.value, 10)">
                    <option v-for="dow in daysOfTheWeek" :value="dow.key" :key="dow.key" :selected="dayOfWeek === dow.key ? true : null">
                        {{ dow.label }}
                    </option>
                </select>
            </label>

            <label :class="{'col-3': !isSingleDay}">
                <span class="required">{{ isSingleDay ? $gettext('Datum') : $gettext('Beginn') }}</span>

                <Datepicker v-model="startDate"
                            name="start-date"
                            :disable-holidays="true"
                            mindate="today"
                            :emit-date="true"
                            return-as="iso"
                ></Datepicker>
            </label>

            <label class="col-3" v-if="!isSingleDay">
                <span class="required">{{ $gettext('Ende') }}</span>

                <Datepicker v-model="endDate"
                            name="end-date"
                            :disable-holidays="true"
                            :mindate="startDate"
                            :emit-date="true"
                            return-as="iso"
                ></Datepicker>
            </label>

            <label for="start-time" :class="{'col-3': !isSingleDate}">
                <span class="required">{{ $gettext('Von') }}</span>

                <Timepicker name="start-time"
                            v-model="startTime"
                            :maxtime="endTime"
                ></Timepicker>
            </label>

            <label for="ende_hour" :class="{'col-3': !isSingleDate}">
                <span class="required">{{ $gettext('Bis') }}</span>

                <Timepicker name="end-time"
                            v-model="endTime"
                            :mintime="startTime"
                ></Timepicker>
            </label>

            <label class="col-3" v-if="!isSingleDate">
                <span class="required">{{ $gettext('Dauer eines Termins in Minuten') }}</span>
                <input required type="number" name="duration" min="1"
                       v-model="duration">
            </label>

            <label :class="{'col-3': !isSingleDate}">
                {{ $gettext('Maximale Teilnehmendenzahl') }}
                <StudipTooltipIcon :text="$gettext('Falls Sie mehrere Personen zulassen wollen (wie z.B. zu einer Klausureinsicht), so geben Sie hier die maximale Anzahl an Personen an, die sich anmelden dürfen.')"></StudipTooltipIcon>
                <input required type="text" name="size" id="size" min="1" max="50"
                       v-model="size">
            </label>

            <label v-if="!isSingleDate">
                <input type="checkbox" name="pause" value="1"
                       v-model="pause">
                {{ $gettext('Pausen zwischen den Terminen einfügen?') }}
            </label>

            <label class="col-3" v-if="!isSingleDate && pause">
                {{ $gettext('Eine Pause nach wie vielen Minuten einfügen?') }}
                <input type="number" name="pause_time" min="1"
                       v-model="pauseTime">
            </label>

            <label class="col-3" v-if="pause">
                {{ $gettext('Dauer der Pause in Minuten') }}
                <input type="number" name="pause_duration" min="1"
                       v-model="pauseDuration">
            </label>

            <label>
                <input type="checkbox" name="lock" value="1"
                       v-model="lock">
                {{ isSingleDate ? $gettext('Termin für Buchungen sperren?') : $gettext('Termin für Buchungen sperren?') }}
            </label>

            <label v-if="lock">
                {{ isSingleDate ? $gettext('Wieviele Stunden vor Beginn des Blocks soll der Termin für Buchungen gesperrt werden?') : $gettext('Wieviele Stunden vor Beginn des Blocks sollen die Termine für Buchungen gesperrt werden?') }}
                <input type="number" name="lock_time" min="1"
                       v-model="lockTime">
            </label>

            <label v-if="!isSingleDate">
                <input type="checkbox" name="consecutive" value="1"
                       v-model="consecutive">
                {{ $gettext('Termine innerhalb der Blöcke nur fortlaufend vergeben') }}
            </label>

            <slot name="extension-point-1"></slot>
        </fieldset>

        <fieldset v-if="withResponsible">
            <legend>{{ $gettext('Durchführende Personen, Gruppen oder Einrichtungen') }}</legend>

            <template v-if="isInstitute">
                <p>
                    {{ $gettext('Bei Einrichtungen muss mindestens eine durchführende Person, Gruppe oder Einrichtung zugewiesen werden.') }}
                </p>
                <p>
                    {{ $gettext('Bitte beachten Sie, dass bei Zuweisungen von Statusgruppen alle Personen der Gruppe mit dem Status '
                        + '"tutor" und "dozent" als durchführende Personen zugewiesen werden und über alle Buchungen '
                        + 'informiert werden.') }}
                    {{ $gettext('Gleiches gilt für eine zugewiesene Einrichtung. Bitte achten Sie darauf, dass Sie Ihre hier '
                        + ' getroffene Auswahl in Absprache tätigen.') }}
                </p>
            </template>

            <template v-if="withResponsible.users">
                <label for="responsible-users">
                    {{ $gettext('Durchführende Personen') }}

                </label>
                <StudipSelect
                    id="responsible-users"
                    v-model="responsibleUsers"
                    :options="withResponsible.users"
                    :reduce="option => option.id"
                    multiple
                    :clearable="true"
                />
            </template>

            <template v-if="withResponsible.groups">
                <label id="responsible-groups">
                    {{ $gettext('Durchführende Gruppen') }}
                </label>
                <StudipSelect
                    id="responsible-groups"
                    v-model="responsibleGroups"
                    :options="withResponsible.groups"
                    :reduce="option => option.id"
                    multiple
                    :clearable="true"
                />
            </template>

            <template v-if="withResponsible.institutes">
                <label for="responsible-institutes">
                    {{ $gettext('Durchführende Einrichtungen') }}
                </label>
                <StudipSelect
                    id="responsible-institutes"
                    v-model="responsibleInstitutes"
                    :options="withResponsible.institutes"
                    :reduce="option => option.id"
                    multiple
                    :clearable="true"
                />
            </template>
        </fieldset>

        <fieldset>
            <legend>{{ $gettext('Weitere Einstellungen') }}</legend>

            <label>
                {{ isSingleDate ? $gettext('Information zu diesem Termin') : $gettext('Information zu den Terminen in diesem Block') }}
                <textarea name="note" v-model="note"></textarea>
            </label>

            <label>
                <input type="checkbox" name="calender-events" value="1"
                       v-model="calendarEvents">
                {{ isSingleDate ? $gettext('Den freien Termin auch im Kalender markieren') : $gettext('Die freien Termine auch im Kalender markieren') }}
            </label>

            <label v-if="isCourse">
                <input type="checkbox" name="mail-to-tutors" value="1"
                       v-model="mailToTutors">
                {{ $gettext('Tutor/innen beim Versand von Buchungsbenachrichtigungen berücksichtigen?') }}
            </label>

            <label>
                <input type="checkbox" name="show-participants" value="1"
                       v-model="showParticipants">
                {{ $gettext('Namen der buchenden Personen sind öffentlich sichtbar') }}
            </label>

            <label>{{ $gettext('Grund der Buchung abfragen') }}</label>
            <div class="hgroup">
                <label>
                    <input type="radio" name="require-reason" value="yes"
                           v-model="requireReason">
                    {{ $gettext('Ja, zwingend erforderlich') }}
                </label>

                <label>
                    <input type="radio" name="require-reason" value="optional"
                           v-model="requireReason">
                    {{ $gettext('Ja, optional') }}
                </label>

                <label>
                    <input type="radio" name="require-reason" value="no"
                           v-model="requireReason">
                    {{ $gettext('Nein') }}
                </label>
            </div>

            <label>
                {{ $gettext('Bestätigung für folgenden Text einholen') }}
                ({{ $gettext('optional') }})
                <StudipTooltipIcon :text="$gettext('Wird hier ein Text eingegeben, so müssen Buchende bestätigen, dass sie diesen Text gelesen haben.')"></StudipTooltipIcon>
                <textarea name="confirmation-text" v-model="confirmationText"></textarea>
            </label>

            <slot name="extension-point-2"></slot>
        </fieldset>

        <fieldset v-if="needsConfirmation">
            <legend>{{ $gettext('Bestätigung der Erstellung vieler Termine') }}</legend>

            <p>
                {{ $gettext('Sie erstellen eine sehr große Anzahl an Terminen.') }}
                {{ $gettext('Bitte bestätigen Sie diese Aktion.') }}
            </p>

            <label>
                <input type="checkbox" v-model="confirmed">
                {{ $gettext(
                    'Ja, ich möchte wirklich %{ n } Termine erstellen.',
                    { n: slotCount }
                ) }}
            </label>
        </fieldset>

        <footer data-dialog-button>
            <button class="accept button" :disabled="room.length === 0 || !confirmed">
                {{ $gettext('Termin speichern') }}
            </button>
            <a :href="cancelUrl" class="cancel button" @click="evt => closeCreator(evt)">
                {{ $gettext('Abbrechen') }}
            </a>
        </footer>
    </form>
</template>
<script>
import StudipTooltipIcon from '@/vue/components/StudipTooltipIcon.vue';
import Datepicker from '@/vue/components/Datepicker.vue';

import moment from 'moment';
import StudipSelect from '@/vue/components/StudipSelect.vue';
import Timepicker from '@/vue/components/Timepicker.vue';

export default {
    name: 'ConsultationCreator',
    components: {Datepicker, StudipSelect, StudipTooltipIcon, Timepicker},
    props: {
        asDialog: {
            type: Boolean,
            default: false,
        },
        cancelUrl: {
            type: String,
            required: true
        },
        defaultRoom: String,
        rangeType: {
            type: String,
            required: true,
        },
        slotCountThreshold: {
            type: Number,
            required: true,
        },
        storeUrl: {
            type: String,
            required: true
        },
        withResponsible: {
            type: [Boolean, Object],
            default: false,
        },
    },
    data() {
        return {
            calendarEvents: false,
            confirmationText: '',
            confirmed: false,
            consecutive: false,
            dayOfWeek: (new Date()).getDay(),
            duration: 15,
            endDate: moment().add(4, 'weeks').toDate(),
            endTime: '09:00',
            errors: [],
            interval: 1,
            lock: false,
            lockTime: 24,
            mailToTutors: true,
            note: '',
            pause: false,
            pauseDuration: 15,
            pauseTime: 45,
            requireReason: 'optional',
            responsibleGroups: [],
            responsibleInstitutes: [],
            responsibleUsers: [],
            room: this.defaultRoom,
            showParticipants: false,
            size: 1,

            slotCount: null,
            startDate: moment().add(1, 'weeks').toDate(),
            startTime: '08:00',
        };
    },
    computed: {
        csrf() {
            return STUDIP.CSRF_TOKEN;
        },
        daysOfTheWeek() {
            return [
                {key: 1, label:  this.$gettext('Montag')},
                {key: 2, label: this.$gettext('Dienstag')},
                {key: 3, label: this.$gettext('Mittwoch')},
                {key: 4, label: this.$gettext('Donnerstag')},
                {key: 5, label: this.$gettext('Freitag')},
                {key: 6, label: this.$gettext('Samstag')},
                {key: 0, label: this.$gettext('Sonntag')},
            ];
        },
        intervals() {
            return [
                {key: -1, label: this.$gettext('Einzeltermin')},
                {key: 0,  label: this.$gettext('Einmalig (ohne Wiederholung)')},
                {key: 1, label: this.$gettext('Wöchentlich')},
                {key: 2, label: this.$gettext('Zweiwöchentlich')},
                {key: 3, label: this.$gettext('Dreiwöchentlich')},
                {key: 4, label: this.$gettext('Monatlich')},
            ];
        },
        isCourse() {
            return this.rangeType === 'Course';
        },
        isInstitute() {
            return this.rangeType === 'Institute';
        },
        isSingleDay() {
            return this.interval === 0
                || this.interval === -1;
        },
        isSingleDate() {
            return this.interval === -1;
        },
        needsConfirmation() {
            return this.slotCount > this.slotCountThreshold;
        },
        recalculationProperty() {
            return [
                this.startDate,
                this.startTime,
                this.endDate,
                this.endTime,
                this.dayOfWeek,
                this.interval,
                this.duration,
                this.pause,
                this.pauseTime,
                this.pauseDuration,
            ].join();
        },
    },
    methods: {
        closeCreator(event) {
            if (this.$el.closest('.studip-dialog')) {
                STUDIP.Dialog.close();
                event.preventDefault();
            }
        },
        compareDates(date0, date1, operator = '=', precision = 'day') {
            const mapping = {
                '<': 'isBefore',
                '<=': 'isSameOrBefore',
                '=': 'isSame',
                '>=': 'isSameOrAfter',
                '>': 'isAfter',
            };

            if (mapping[operator] === undefined) {
                throw new Error(`Unsupported operator '${operator}'`);
            }

            const compareDate0 = moment(date0);
            const compareDate1 = moment(date1);

            const method = mapping[operator];
            return compareDate0[method](compareDate1, precision);
        },
        validateInputs(event) {
            const errors = [];

            if (this.startTime > this.endTime) {
                errors.push(this.$gettext('Die Endzeit liegt vor der Startzeit!'));
            }

            if (!this.isSingleDay && this.compareDates(this.startDate, this.endDate, '>')) {
                errors.push(this.$gettext('Das Enddatum liegt vor dem Startdatum!'));
            }

            if (!this.isSingleDate && this.pause && this.pauseTime < this.duration) {
                errors.push(this.$gettext('Die definierte Zeit bis zur Pause ist kleiner als die Dauer eines Termins.'));
            }

            if (
                this.isInstitute
                && this.responsibleGroups.length === 0
                && this.responsibleInstitutes.length === 0
                && this.responsibleUsers.length === 0
            ) {
                errors.push(this.$gettext('Es muss mindestens eine durchführende Person, Statusgruppe oder Einrichtung ausgewählt werden.'));
            }

            if (this.needsConfirmation && !this.confirmed) {
                errors.push(this.$gettext('Sie müssen bestätigen, dass sie eine große Anzahl von Terminen erstellen möchten.'));

            }

            if (errors.length > 0) {
                this.errors = errors;
                event.preventDefault();
            }
        },
        combineDateAndTime(date, time) {
            const [hour, minute] = time.split(':').map(item => parseInt(item, 10));
            const result = new Date(date);
            result.setHours(hour, minute, 0, 0);
            return result;
        }
    },
    watch: {
        interval(current, previous) {
            if (current === 0 || current === -1) {
                this.endDate = new Date(this.startDate);
            }

            if (current === -1) {
                const start = this.combineDateAndTime(this.startDate, this.startTime);
                const end = this.combineDateAndTime(this.endDate, this.endTime);
                this.duration = Math.floor((end - start) / 1000 / 60);
            }

            if (current !== -1 && previous === -1) {
                this.duration = 15;
            }
        },
        recalculationProperty: {
            handler() {
                const start = this.combineDateAndTime(this.startDate, this.startTime).toISOString();
                const end = this.combineDateAndTime(this.endDate, this.endTime).toISOString();

                if (start >= end) {
                    this.slotCount = 0;
                    this.confirmed = false;
                } else if (this.interval === -1) {
                    this.slotCount = 1;
                    this.confirmed = true;
                } else {
                    STUDIP.jsonapi.withPromises().GET('consultation-slots/count', {
                        data: {
                            start,
                            end,
                            dow: this.dayOfWeek,
                            interval: this.interval,
                            duration: this.duration,
                            pause_time: this.pause ? this.pauseTime : null,
                            pause_duration: this.pause ? this.pauseDuration : null,
                        }
                    }).then(
                        (count) => {
                            this.slotCount = count;
                            this.confirmed = count <= this.slotCountThreshold;
                        },
                        () => null
                    );
                }
            },
            immediate: true
        },
        startDate(current) {
            this.dayOfWeek = current.getDay();

            if (this.interval === 0 || this.interval === -1) {
                this.endDate = new Date(current);
            }
        },
    },
    beforeCreate() {
        STUDIP.Vue.emit('ConsultationCreatorWillCreate', this);
    }
}
</script>
<style scoped>
form.default label input[type="time"] {
    max-width: 48em;
}
</style>
