<script lang="ts">
import { computed, shallowRef, type PropType } from 'vue';
import { Date, DateTime, add, sub, timedelta } from '@silane/datetime';

import { inject, keys as injectionKeys } from '../../../../../injection';
import { datetimeRange } from '../../../../../common/utils.js';
import {
  type Event, eventToEventInput,
} from '../../../../../composables/eventstore';


function copyEvent(sourceEvent: Event, newDate: Date) {
  const startTime = DateTime.combine(newDate, sourceEvent.startTime.timetz());
  const endTime = add(
    startTime, sub(sourceEvent.endTime, sourceEvent.startTime)
  );
  return { ...eventToEventInput(sourceEvent), startTime, endTime };
}

export default {
  name: 'PageMasterTimetableEventsIndex_CopyEventsByDayOfWeekDialog',
  props: {
    sourceEvents: { type: Array as PropType<Event[]>, required: true },
  },
  emits: ['run'],
  setup(props, { emit }) {
    const handleError = inject(injectionKeys.errorHandler).handleErrorAsync;
    const eventStore = inject(injectionKeys.eventStore);

    const sourceEventDaysByDayOfWeek = computed(() => {
      const ret = Array.from({ length: 7 }, () => new Set<string>());
      for(const event of props.sourceEvents) {
        ret[event.startTime.weekday()].add(event.startTime.date().isoFormat());
      }
      return ret.map(x => [...x].map(y => Date.fromISOFormat(y)));
    });

    const today = Date.today();
    const copyDestinationDateRange = shallowRef<[Date, Date]>(
      [today, add(today, timedelta({ days: 1 }))]
    );

    const submit = handleError(async () => {
      const eventsByWeekDays = Array.from({ length: 7 }, (): Event[] => []);
      for(const event of props.sourceEvents) {
        eventsByWeekDays[event.startTime.weekday()].push(event);
      }

      await eventStore.mutate([...datetimeRange(
        ...copyDestinationDateRange.value, timedelta({ days: 1 })
      )].flatMap(
        date => eventsByWeekDays[date.weekday()].map(x => copyEvent(x, date))
      ).map(x => ({ opcode: 'add_event', param: x })));
      emit('run');
    });

    return {
      add, timedelta, sourceEventDaysByDayOfWeek, copyDestinationDateRange,
      submit,
    };
  }
}
</script>

<template>
<h1>曜日別複製</h1>
<p>選択したイベントを指定の日付範囲の同じ曜日に複製します。振替・取消の情報は無視されます。</p>
<div v-show="
  sourceEventDaysByDayOfWeek.some(x => x.length > 1)
" class="duplicateweekdays">
  <p>
    複製元イベントの中に、同じ曜日だが異なる日付のイベントが含まれています。
    イベントの重複に注意してください。
  </p>
  <dl>
    <div v-for="[weekdayIdx, dates] of sourceEventDaysByDayOfWeek.map(
      (x, weekdayIdx) => [weekdayIdx, x] as const
    ).filter(x => x[1].length > 1)" :key="weekdayIdx">
      <dt>{{ ['月', '火', '水', '木', '金', '土', '日'][weekdayIdx] }}曜日</dt>
      <dd>
        <ul class="duplicateweekdays-dateslist">
          <li v-for="date of dates" :key="date.isoFormat()">
            <date-time :value="date" />
          </li>
        </ul>
      </dd>
    </div>
  </dl>
</div>
<form @submit.prevent="submit()">
  <label>
    複製先日付範囲
    <span style="display: flex; justify-content: center;">
      <input-date-range v-model="copyDestinationDateRange" :inline="true" />
    </span>
  </label>
  <p style="text-align: end;">
    <button>
      <date-time :value="copyDestinationDateRange[0]" /> から
      <date-time :value="add(
        copyDestinationDateRange[1], timedelta({ days: -1 })
      )" />
      の範囲に複製実行
    </button>
  </p>
</form>
</template>

<style scoped>
.duplicateweekdays {
  padding: .1em .5em;
  border-radius: 1em;
  background-color: #ff000020;
}
.duplicateweekdays-dateslist {
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .5em;
  list-style: none;
}
</style>
