<script lang="ts">
import { DateTime, time, timedelta } from '@silane/datetime';
import { computed, shallowRef, watch } from 'vue';
import { onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router';

import InputTeacherLessonList, {
  ModelValueErrorsPropType,
} from '../../../../../components/InputTeacherLessonList.vue';
import { inject, keys as injectionKeys } from '../../../../../injection';
import { datetimeRange } from '../../../../../common/utils.js';
import { getResourceDisplayText } from '../../../../../common/zkan-utils.js';
import {
  useEmphasizeHashElement,
} from '../../../../../composables/emphasize-element-of-url-hash';
import { Event, eventToEventInput } from '../../../../../composables/eventstore';

type LessonEvent = Extract<Event, { type: 'lesson' }>

function isLesson(x: Event): x is LessonEvent {
  return x.type === 'lesson';
}

export default {
  name: 'PageMasterTimetableResourcesIdLessons',
  components: { InputTeacherLessonList },
  props: {
    id: { type: String, required: true },
  },
  setup(props) {
    useEmphasizeHashElement();
    const notification = inject(injectionKeys.notification);
    const handleError = inject(injectionKeys.errorHandler).handleErrorAsync;
    const resourceStore = inject(injectionKeys.resourceStore);
    const eventStore = inject(injectionKeys.eventStore);
    const generalTimetableScope = inject(injectionKeys.generalTimetableScope);

    const classroom = computed(() => resourceStore.resources.value.find(
      x => x.id === generalTimetableScope.classroom.value
    )!);
    const resource = computed(() => resourceStore.resources.value.find(
      x => x.id === props.id
    ) ?? null);
    const dates = computed(() => [...datetimeRange(
      ...generalTimetableScope.dateRange.value, timedelta({ days: 1 })
    )]);

    const loading = shallowRef(false);
    const downloadedEvents = shallowRef<Event[]>([]);
    const load = handleError(async () => {
      loading.value = true;
      downloadedEvents.value = await eventStore.query({
        startTime: DateTime.combine(
          generalTimetableScope.dateRange.value[0], time()
        ), endTime: DateTime.combine(
          generalTimetableScope.dateRange.value[1], time()
        )
      });
      loading.value = false;
    });

    watch(generalTimetableScope.dateRange, async () => {
      await load();
    }, { immediate: true });

    const storeEvents = computed(() => !resource.value
      ? [] : downloadedEvents.value.filter(isLesson).filter(x => [
        resource.value?.id, generalTimetableScope.classroom.value
      ].every(rId => x.resources.some(r => r.id === rId)))
    );

    const events = shallowRef<LessonEvent[]>([]);
    watch(storeEvents, () => {
      events.value = storeEvents.value;
    }, { immediate: true });

    const notSupportedEventErrors = shallowRef<ModelValueErrorsPropType>([]);
    const lessonInputInvalid = shallowRef(false);

    watch(notSupportedEventErrors, () => {
      if(!notSupportedEventErrors.value.length) return;
      notification.add('error', '予期しないエラーが発生しました', JSON.stringify(
        notSupportedEventErrors.value.map(x => ({ code: x.code, event: x.event.id })))
      );
    });

    const save = handleError(async () => {
      if(lessonInputInvalid.value) {
        notification.add('error', '入力欄にエラーがあります');
        return false;
      }

      const eventsToAdd = events.value.filter(x => x.id == null);
      const eventsToUpdate = events.value.filter(x => x.id != null);
      const eventsToRemove = storeEvents.value.filter(
        x => !events.value.some(e => e.id === x.id)
      );

      await eventStore.mutate([...eventsToAdd.map(x => ({
        opcode: 'add_event' as const, param: eventToEventInput(x),
      })), ...eventsToUpdate.map(x => ({
        opcode: 'update_event' as const, param: {
          id: x.id, ...eventToEventInput(x),
        },
      })), ...eventsToRemove.map(x => ({
        opcode: 'remove_event' as const, param: { id: x.id },
      }))]);
      notification.add('info', '保存しました');

      await load();

      return true;
    });
    onBeforeRouteUpdate(async (to, from) => {
      if(to.params.id === from.params.id) return;
      if(!await save()) return false;
    });
    onBeforeRouteLeave(async () => {
      if(!await save()) return false;
    });

    return {
      getResourceDisplayText, classroom, resource, dates, loading, events,
      notSupportedEventErrors, load, save,
    };
  },
}
</script>

<template>
<p v-if="!resource">リソースが見つかりません。</p>
<template v-else>
  <h1>
    <router-link
      to="./index"
    >{{ getResourceDisplayText(resource) }}</router-link>の授業入力
  </h1>
  <p v-if="loading">読み込み中</p>
  <p v-else-if="resource.type !== 'teacher'">講師以外の種別のリソースは扱えません。</p>
  <template v-else>
    <p>
      変更は<router-link to="#savebutton">「保存」ボタン</router-link>を押すかページ遷移時に自動で保存されます。
    </p>
    <input-teacher-lesson-list
      v-model="events" v-model:modelValueErrors="notSupportedEventErrors" :dates="dates"
      :event-initial-value="{ resources: [classroom, resource] }"
    />
    {{ events.length }}
    <p><button type="button" @click="save()" id="savebutton">保存</button></p>
    <p><button type="button" @click="load()">最後に保存した時の状態にリセット</button></p>
  </template>
</template>
</template>
