<script>
import { computed, watch, shallowRef } from 'vue';
import { DateTime, cmp, time } from '@silane/datetime';

import { getResourceDisplayText } from '../../../common/zkan-utils.js';
import { getTimeLine } from '../../../common/timeline';
import { inject, keys as injectionKeys } from '../../../injection';


export default {
  name: "PageMasterTimetableEventintegrity",
  setup() {
    const handleError = inject(injectionKeys.errorHandler).handleErrorAsync;
    const resourceHourStore = inject(injectionKeys.resourceHourStore);
    const eventStore = inject(injectionKeys.eventStore);
    const generalTimetableScope = inject(injectionKeys.generalTimetableScope);

    const loading = shallowRef(false);
    const timelines = shallowRef(/** @type {{
      resource: import('../../../composables/resourcestore').Resource,
      timeline: ReturnType<typeof getTimeLine>,
    }[]} */([]));

    const load = handleError(async () => {
      loading.value = true;

      const events = (await eventStore.query({ startTime: DateTime.combine(
        generalTimetableScope.dateRange.value[0], time()
      ), endTime: DateTime.combine(
        generalTimetableScope.dateRange.value[1], time()
      ) })).filter(x => x.resources.some(
        r => r.id === generalTimetableScope.classroom.value
      ) && !x.eventChangeTo);

      const resources = [...new Map(
        events.flatMap(x => x.resources).map(x => [x.id, x])
      ).values()].filter(x => !x.disabled);

      const resourceHours = await Promise.all(resources.map(
        x => resourceHourStore.query({
          resource: x.id, startTime: DateTime.combine(
            generalTimetableScope.dateRange.value[0], time()
          ),
          endTime: DateTime.combine(
            generalTimetableScope.dateRange.value[1], time()
          ),
        })
      ));

      timelines.value = resources.map((resource, resourceIdx) => ({
        resource, timeline: getTimeLine(events.filter(
          event => event.resources.some(x => x.id === resource.id)
        ), resourceHours[resourceIdx], DateTime.min, DateTime.max)
      }));

      loading.value = false;
    });

    watch([
      generalTimetableScope.classroom, generalTimetableScope.dateRange
    ], () => { load(); }, { immediate: true });

    const collisionErrors = computed(() => timelines.value.filter(
      ({ resource }) => resource.multiplicity >= 0
    ).flatMap(({ resource, timeline }) => timeline.filter(
      x => x.events.length > resource.multiplicity
    ).map(x => ({
      resource, startTime: x.startTime, endTime: x.endTime,
      events: x.events,
    }))));

    const outOfHourErrors = computed(() => timelines.value.flatMap(({
      resource, timeline,
    }) => timeline.filter(
      x => x.events.length > 0 && !x.available
    ).flatMap(segment => segment.events.map(event => ({
      resource, event, 
      startTime: segment.startTime, endTime: segment.endTime,
    })))));

    return {
      loading, collisionErrors, outOfHourErrors, getResourceDisplayText, cmp,
    };
  },
};
</script>

<template>
<div>
  <h1>整合性チェック</h1>
  <p v-if="loading">読み込み中</p>
  <template v-else>
    <section>
      <h1>衝突</h1>
      <template v-if="collisionErrors.length !== 0">
      <p>
        「リソース」が「開始時刻」と「終了時刻」の間で複数のイベントで使われています。
        それらのイベントは「イベント」で示されています。
      </p>
      <DataGrid
        :modelValue="collisionErrors"
        :itemKey="x => `${x.resource.id}-${x.startTime.isoFormat()}`"
        :headers="[
          {text: 'イベント', value: 'events'},
          {text: 'リソース', value: 'resource', sort: (a, b) => a.id - b.id},
          {text: '開始時刻', value: 'startTime', sort: (a, b) => cmp(a, b)},
          {text: '終了時刻', value: 'endTime', sort: (a, b) => cmp(a, b)},
        ]">
        <template v-slot:td-イベント="{data}">
          <template v-for="event in data" :key="event.id">
            [<EventLink :event="event" />]
          </template>
        </template>
        <template v-slot:td-リソース="{data}">
          {{ getResourceDisplayText(data) }}
        </template>
        <template v-slot:td-開始時刻="{data}">
          <DateTime :value="data" />
        </template>
        <template v-slot:td-終了時刻="{data}">
          <DateTime :value="data" />
        </template>
      </DataGrid>
      </template>
      <span v-else>衝突しているイベントはありません</span>
    </section>
    <section>
      <h1>時間外</h1>
      <template v-if="outOfHourErrors.length !== 0">
      <p>
        「リソース」が使用可能時間外の「開始時刻」と「終了時刻」の間で使われています。
        使われているイベントは「イベント」で示されています。
      </p>
      <DataGrid
        :modelValue="outOfHourErrors"
        :itemKey="x => `${x.resource.id}-${x.event.id}`"
        :headers="[
          {text: 'イベント', value: 'event', sort: (a, b) => a.id - b.id},
          {text: 'リソース', value: 'resource', sort: (a, b) => a.id - b.id},
          {text: '開始時刻', value: 'startTime', sort: (a, b) => cmp(a, b)},
          {text: '終了時刻', value: 'endTime', sort: (a, b) => cmp(a, b)},
        ]">
        <template v-slot:td-イベント="{data}">
          [<EventLink :event="data" />]
        </template>
        <template v-slot:td-リソース="{data}">
          {{ getResourceDisplayText(data) }}
        </template>
        <template v-slot:td-開始時刻="{data}">
          <DateTime :value="data" />
        </template>
        <template v-slot:td-終了時刻="{data}">
          <DateTime :value="data" />
        </template>
      </DataGrid>
      </template>
      <span v-else>時間外のイベントはありません</span>
    </section>
  </template>
</div>
</template>
