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

import {
  useEmphasizeHashElement,
} from '../../../../../composables/emphasize-element-of-url-hash.js';
import { inject, keys as injectionKeys } from '../../../../../injection';
import {
  datetimeRange, dateAndTimeRangeToDateTimeRange,
} from '../../../../../common/utils.js';
import { getResourceDisplayText } from '../../../../../common/zkan-utils.js';
import { TimeTable } from '../../../../../common/timetable';


export default {
  name: 'PageMasterTimetableResourcesIdResourcehours',
  props: {
    id: { type: String, required: true },
  },
  setup(props) {
    useEmphasizeHashElement();
    const notification = inject(injectionKeys.notification);
    const resourceStore = inject(injectionKeys.resourceStore);
    const resourceHourStore = inject(injectionKeys.resourceHourStore);
    const generalTimetableScope = inject(injectionKeys.generalTimetableScope);

    const resource = computed(() => resourceStore.resources.value.find(
      x => x.id === props.id
    ) ?? null);

    const dateRange = generalTimetableScope.dateRange;
    const dates = computed(() => [...datetimeRange(
      ...generalTimetableScope.dateRange.value, timedelta({ days: 1 })
    )]);

    const timeRanges = shallowRef(/** @type {{
      startTime: import('@silane/datetime').DateTime,
      endTime: import('@silane/datetime').DateTime,
    }[]} */([]));
    const dailyTimeRangesInvalid = shallowRef(false);
    const view = shallowRef(/** @type {'daily' | 'weekly'} */('daily'));

    async function load() {
      if(!resource.value) return;
      timeRanges.value = await resourceHourStore.query({
        resource: resource.value.id, startTime: DateTime.combine(
          dateRange.value[0], time()
        ), endTime: DateTime.combine(dateRange.value[1], time()),
      });
    }

    watch([resource, dates], async () => {
      await load();
    }, { immediate: true });

    const dailyTimeRanges = computed({ get: () => {
      const timetable = new TimeTable();
      for(const range of timeRanges.value) {
        timetable.add(range.startTime, range.endTime, true);
      }
      return [...datetimeRange(
        ...generalTimetableScope.dateRange.value, timedelta({ days: 1 })
      )].map(date => {
        return { date, timeRanges: timetable.get(
          ...dateAndTimeRangeToDateTimeRange(date, time(), time())
        ).filter(x => x.items.has(true)).map(x => ({
          startTime: x.start.timetz(), endTime: x.end.timetz(),
        })) };
      });
    }, set: val => {
      const timetable = new TimeTable();
      for(const { date, timeRanges } of val) {
        for(const timeRange of timeRanges) {
          timetable.add(...dateAndTimeRangeToDateTimeRange(
            date, timeRange.startTime, timeRange.endTime,
          ), true);
        }
      }
      timeRanges.value = timetable.get().filter(
        x => x.items.has(true)
      ).map(x => ({ startTime: x.start, endTime: x.end }));
    }});

    async function save() {
      /**
       * @param {[DateTime, DateTime]} range
       */
      function timeRangeTupleToObject(range) {
        return { startTime: range[0], endTime: range[1] };
      }

      if(dailyTimeRangesInvalid.value) {
        notification.add('error', '日付別時間帯入力欄にエラーがあります');
        return false;
      }
      await resourceHourStore.mutate([...dailyTimeRanges.value.map(x => ({
        opcode: 'unfill', param: {
          resource: resource.value.id, ...timeRangeTupleToObject(
            dateAndTimeRangeToDateTimeRange(x.date, time(), time())
          ),
        },
      })), ...dailyTimeRanges.value.flatMap(x => x.timeRanges.map(r => ({
        ...timeRangeTupleToObject(
          dateAndTimeRangeToDateTimeRange(x.date, r.startTime, r.endTime)
        ),
      }))).map(x => ({
        opcode: 'fill', param: { resource: resource.value.id, ...x },
      }))]);
      notification.add('info', '保存しました');
      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, resource, dates, timeRanges, dailyTimeRanges,
      dailyTimeRangesInvalid, view, load, save,
    };
  },
}
</script>

<template>
<template v-if="resource">
<h1>
  <router-link
      to="./index"
  >{{ getResourceDisplayText(resource) }}</router-link>の可能時間入力
</h1>
<p>
  変更は<router-link to="#savebutton">「保存」ボタン</router-link>を押すかページ遷移時に自動で保存されます。
</p>
<label><input type="radio" name="view" v-model="view" value="daily" />日付毎入力</label>
<label><input type="radio" name="view" v-model="view" value="weekly" />一括入力</label>
<div v-show="view === 'daily'">
  <!-- <p>一日に2つまでの時間範囲を指定できます。</p> -->
  <!-- <input-daily-time-ranges
    v-model="dailyTimeRanges" v-model:invalid="dailyTimeRangesInvalid"
  /> -->
  <input-daily-time-ranges v-model="timeRanges" :dates="dates" style="height: calc(100vh - 5em);" />
</div>
<input-calendar-time-ranges
  v-show="view ==='weekly'" v-model="timeRanges" :dates="dates"
/>
<hr />
<p><button type="button" @click="save()" id="savebutton">保存</button></p>
<p><button type="button" @click="load()">最後に保存した時の状態にリセット</button></p>
</template>
<p v-else>無効なリソースIDが指定されています。</p>
</template>
