<script lang="ts">
import { Date, DateTime, add, timedelta, time, cmp } from '@silane/datetime';
import { ref, computed, markRaw, shallowRef } from 'vue';

import InputResourceMultiSelect from '../../../components/InputResourceMultiSelect.vue';
import { inject, keys as injectionKeys } from '../../../injection';
import { datetimeRange, groupBy } from '../../../common/utils.js';
import { getResourceDisplayText } from '../../../common/zkan-utils.js';
import type { Resource } from '../../../composables/resourcestore';


function dateToDateTimeRange(date: Date) {
  return {
    startTime: DateTime.combine(date, time()),
    endTime: DateTime.combine(add(date, timedelta({ days: 1 })), time()),
  };
}

export default {
  name: 'PageMasterTimetableResourcehourcopy',
  components: { InputResourceMultiSelect },
  setup() {
    const handleError = inject(injectionKeys.errorHandler).handleErrorAsync;
    const notification = inject(injectionKeys.notification);
    const resourceStore = inject(injectionKeys.resourceStore);
    const resourceHourStore = inject(injectionKeys.resourceHourStore);

    const today = Date.today();
    const resources = computed(
      () => resourceStore.resources.value.filter(x => !x.disabled)
    );

    const srcDates = shallowRef<Date[]>([]);
    const targetResources = ref<Resource[]>([]);
    const dstDateRange = shallowRef<[Date, Date]>(
      [markRaw(today), markRaw(add(today, timedelta({ days: 1 })))]
    );

    const errors = computed(() => {
      return groupBy(srcDates.value, x => x.weekday()).filter(
        x => x.items.length > 1
      ).map(x => ({ code: 'duplicateSrcDayOfWeek', param: x.items}));
    });

    const submit = handleError(async () => {
      if(errors.value.length) {
        notification.add('error', '入力欄にエラーがあります');
        return;
      }
      const dayofweekToSourceDates = Array.from(
        { length: 7 }, (_, i) => i
      ).map(x => srcDates.value.find(d => d.weekday() == x) ?? null);
      const source = await Promise.all(dayofweekToSourceDates.map(
        date => !date ? null : Promise.all(targetResources.value.map(
          resource => resourceHourStore.query({
            resource: resource.id, startTime: DateTime.combine(date, time()),
            endTime: DateTime.combine(add(date, timedelta({ days: 1 })), time()),
          })
        ))
      ));
      await resourceHourStore.mutate(
        [...datetimeRange(
          ...dstDateRange.value, timedelta({ days: 1 })
        )].filter(date => source[date.weekday()]).flatMap(
          date => targetResources.value.flatMap((resource, resourceIdx) => [{
            opcode: 'unfill' as const, param: {
              resource: resource.id, ...dateToDateTimeRange(date),
            },
          }, ...source[date.weekday()]![resourceIdx].map(x => ({
            opcode: 'fill' as const, param: {
              resource: resource.id,
              startTime: DateTime.combine(date, x.startTime.timetz()),
              endTime: DateTime.combine(date, x.endTime.timetz()),
            }
          }))])
        )
      );
      notification.add('info', '完了しました');
    });

    return {
      cmp, add, timedelta, getResourceDisplayText,
      resources, srcDates, targetResources,
      dstDateRange, errors, submit,
    };
  },
}
</script>

<template>
<h1>可能時間曜日別一括複製</h1>
<form @submit.prevent="submit">
  <p>
    コピー元日付（複数選択可）
    <input-multi-dates v-model="srcDates" />
  </p>
  <p>
    <label>
      リソース
      <input-resource-multi-select
        v-model="targetResources" :options="resources"
      />
    </label>
  </p>
  <p>
    コピー先日付範囲
    <input-date-range v-model="dstDateRange" />
  </p>
  <ul v-if="errors.length">
    <li v-for="error of errors">
      <template v-if="error.code === 'duplicateSrcDayOfWeek'">
        コピー元日付に同じ曜日の日付、<date-time v-for="d of error.param" :value="d" />が含まれています。
      </template>
    </li>
  </ul>
  <p v-else>
    <output v-if="srcDates.length === 0">コピー元日付を一つ以上選択してください。</output>
    <output v-else-if="targetResources.length === 0">
      リソースを一つ以上選択してください。
    </output>
    <output v-else>
      {{ targetResources.map(getResourceDisplayText).join(', ') }}について、
      <date-time :value="dstDateRange[0]" />～<date-time :value="add(
        dstDateRange[1], timedelta({ days: -1})
      )" />の
      <template v-for="date of srcDates.sort(
        (a, b) => cmp(a, b)
      )" :key="date.isoFormat()">
        {{
          ['月', '火', '水', '木', '金', '土', '日'][date.weekday()]
        }}曜日の可能時間を<date-time :value="date" />から、
      </template>コピーします。
    </output>
  </p>
  <p>
    <button>実行</button>
  </p>
</form>
</template>
