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

import InputEvent, {
  type ModelValuePropType as InputEventModelValuePropType,
} from '../../../../../components/InputEvent.vue';
import { inject, keys as injectionKeys } from '../../../../../injection';
import { getResourceDisplayText } from '../../../../../common/zkan-utils.js';
import {
  eventToEventInput, type Event,
} from '../../../../../composables/eventstore';


function datetimeFloor(datetime: DateTime): DateTime {
  return DateTime.combine(datetime.date(), time());
}
function datetimeCeil(datetime: DateTime): DateTime {
  return DateTime.combine(add(datetime.date(), timedelta({
    days: cmp(datetime.time(), time()) === 0 ? 0 : 1,
  })), time());
}

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

    const fromEvent = shallowRef<Event | null>(null);
    const load = handleError(async () => {
      const resp = await eventStore.query({ id: props.id });
      fromEvent.value = resp.find(
        x => x.id === props.id
      ) ?? null;
    });
    watch(() => props.id, load, { immediate: true });

    const eventChangeView = ref<'' | 'change' | 'cancel'>('');
    const causeResources = ref<string[]>([]);
    const resourceHourModification = ref<'none' | 'time' | 'day'>('none');

    const toEvent = shallowRef<InputEventModelValuePropType>({
      type: 'standard', resources: [], startTime: DateTime.combine(
        generalTimetableScope.dateRange.value[0], time()
      ), endTime: DateTime.combine(
        generalTimetableScope.dateRange.value[0], time()
      ), timeLabel: null, color: '#FFFFFF', memo: '',
    });
    const toEventInvalid = ref(false);

    watch(fromEvent, async () => {
      if(!fromEvent.value) return;
      toEvent.value = fromEvent.value;
    }, { immediate: true });

    const removeEvent = handleError(async () => {
      if(!fromEvent.value) return;
      if(!confirm('本当に削除しますか？')) return;
      await eventStore.mutate([{
        opcode: 'remove_event', param: { id: fromEvent.value.id },
      }]);
      notification.add('info', '削除しました');
      await load();
    });

    const changeEvent = handleError(async (type: 'change' | 'cancel') => {
      if(!fromEvent.value) return;
      if(type === 'change') {
        if(toEventInvalid.value) {
          notification.add('error', '振替先の入力欄にエラーがあります');
          return;
        }

        const newEvent = { ...eventToEventInput(toEvent.value), __id: 'A' };
        await eventStore.mutate([{
          opcode: 'add_event', param: newEvent,
        }, {
          opcode: 'add_eventchange', param: {
            fromEvent: { id: fromEvent.value.id },
            toEvent: { __id: newEvent.__id },
            causeResources: causeResources.value,
          },
        }]);
      } else if(type === 'cancel') {
        await eventStore.mutate([{
          opcode: 'add_eventchange', param: {
            fromEvent: { id: fromEvent.value.id },
            toEvent: null, causeResources: causeResources.value,
          },
        }]);
      }

      const resourceHourRangeToUnfill = (
        resourceHourModification.value === 'time' ? {
          startTime: fromEvent.value.startTime, endTime: fromEvent.value.endTime,
        } : resourceHourModification.value === 'day' ? {
          startTime: datetimeFloor(fromEvent.value.startTime),
          endTime: datetimeCeil(fromEvent.value.endTime),
        } : null
      );
      if(resourceHourRangeToUnfill) {
        await resourceHourStore.mutate(causeResources.value.map(x => ({
          opcode: 'unfill', param: {
            ...resourceHourRangeToUnfill, resource: x,
          },
        })));
      }

      await load();
    });

    const removeEventChange = handleError(async () => {
      if(!fromEvent.value) return;
      await eventStore.mutate([{
        opcode: 'remove_eventchange',
        param: { fromEvent: { id: fromEvent.value.id }},
      }]);
      await load();
    });

    return {
      getResourceDisplayText, fromEvent, eventChangeView, causeResources,
      resourceHourModification, toEvent, toEventInvalid,
      removeEvent, changeEvent, removeEventChange,
    };
  }
}
</script>

<template>
  <h1>イベント {{ fromEvent?.id }}</h1>
  <p v-if="!fromEvent">無効なイベントが指定されています。</p>
  <template v-else>
    <p><router-link to="./edit">編集</router-link></p>
    <p><button type="button" @click="removeEvent()">このイベントを削除</button></p>
    <dl>
      <dt>ID</dt><dd>{{ fromEvent.id }}</dd>
      <dt>種別</dt>
      <dd>{{ { standard: '標準', lesson: '授業' }[fromEvent.type] }}</dd>
      <dt>リソース</dt>
      <dd>
        <ul>
          <li v-for="resource of fromEvent.resources" :key="resource.id">
            <router-link
              :to="`/master/timetable/resources/${resource.id}/index`"
            >{{ getResourceDisplayText(resource) }}</router-link>
          </li>
        </ul>
      </dd>
      <dt>時刻</dt>
      <dd>
        <DateTime :value="fromEvent.startTime" />
        -
        <DateTime :value="fromEvent.endTime" />
        <template v-if="fromEvent.timeLabel">
          ({{ fromEvent.timeLabel.label }})
        </template>
      </dd>
      <dt>メモ</dt><dd>{{ fromEvent.memo }}</dd>
      <dt>色</dt>
      <dd>
        <span
          class="colorbox" :style="{ '--colorbox-color': fromEvent.color }"
        ></span>
        {{ fromEvent.color }}
      </dd>
      <template v-if="fromEvent.type === 'lesson'">
        <dt>教科</dt><dd>{{ fromEvent.subject }}</dd>
        <dt>枠</dt><dd>{{ fromEvent.frame }}</dd>
      </template>
      <template v-if="fromEvent.eventChangeFrom">
        <dt>振替元</dt>
        <dd>
          このイベントは<EventLink :event="fromEvent.eventChangeFrom.fromEvent">別のイベント</EventLink>の振替先です<br />
          原因リソース: {{
            fromEvent.eventChangeFrom.causeResources.map(
              getResourceDisplayText
            ).join(', ')
          }}
        </dd>
      </template>
    </dl>
    <section>
      <h1>振替 / 取消</h1>
      <template v-if="fromEvent.eventChangeTo">
        <p v-if="fromEvent.eventChangeTo.toEvent">
          このイベントは<EventLink :event="fromEvent.eventChangeTo.toEvent">別のイベント</EventLink>に振替済みです。<br />
          振替先を変えるには振替先のイベントを編集してください。振替を削除するには振替先のイベントを削除してください。<br />
          原因リソース: {{
            fromEvent.eventChangeTo.causeResources.map(
              getResourceDisplayText
            ).join(', ')
          }}
        </p>
        <p v-else>
          このイベントは取消済みです。<br />
          原因リソース: {{
            fromEvent.eventChangeTo.causeResources.map(
              getResourceDisplayText
            ).join(', ')
          }}<br />
          <button type="button" @click="removeEventChange()">取消を取り消す</button>
        </p>
      </template>
      <template v-else>
        <button type="button" @click="eventChangeView = 'cancel'">このイベントを取り消す</button>
        <button type="button" @click="eventChangeView = 'change'">このイベントを振り替える</button>

        <form v-if="eventChangeView" @submit.prevent="changeEvent(eventChangeView)">
          <section>
            <h1>振替/取消設定</h1>
            <fieldset>
              <legend>原因リソース（どのリソースの都合で振替/取消するのか）</legend>
              <label v-for="resource of fromEvent.resources" :key="resource.id">
                <input
                  type="checkbox" :value="resource.id" v-model="causeResources"
                /> {{ getResourceDisplayText(resource) }}
              </label>
            </fieldset>
            <label>
              可能時間修正:
              <select v-model="resourceHourModification">
                <option value="none">行わない</option>
                <option value="time">「原因リソース」で指定されたリソースについて変更元の時刻を可能時間から外す</option>
                <option value="day">「原因リソース」で指定されたリソースについて変更元の日付全体を可能時間から外す</option>
              </select>
            </label>
          </section>
          <section v-if="eventChangeView === 'change'">
            <h1>振替先イベント</h1>
            <input-event v-model="toEvent" v-model:invalid="toEventInvalid" />
          </section>
          <p>
            <button>
              {{ { change: '振替', cancel: '取消' }[eventChangeView] }}実行
            </button>
          </p>
        </form>
      </template>
    </section>
  </template>
</template>

<style scoped>
.colorbox {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: solid 1px #000000;
  background-color: var(--colorbox-color);
}
</style>
