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

import InputTimeLabel from '../../../../../components/InputTimeLabel.vue';
import InputEventColor from '../../../../../components/InputEventColor.vue';
import InputResourceMultiSelect from '../../../../../components/InputResourceMultiSelect.vue';
import { inject, keys as injectionKeys } from '../../../../../injection';
import { getResourceDisplayText } from '../../../../../common/zkan-utils.js';
import {
  type Event, eventToEventInput,
} from '../../../../../composables/eventstore';
import type { TimeLabel } from '../../../../../composables/timelabelstore';
import type { Resource } from '../../../../../composables/resourcestore';


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

    const sourceEventsIncludesLesson = computed(
      () => props.sourceEvents.some(x => x.type === 'lesson')
    );

    const dateShift = ref(0);
    const timeChangeMode = ref<
      'nochange' | 'timelabelset' | 'timeshift'
    >('nochange');
    const timeShift = ref(0);
    const timeLabel = shallowRef<TimeLabel | null>(null);
    const resourceChangeMode = ref<
      'nochange' | 'lesson' | 'general'
    >('nochange');
    const teacher = shallowRef<Resource | null>(null);
    const student = shallowRef<Resource | null>(null);
    const resourcesToAdd = shallowRef<Resource[]>([]);
    const resourcesToRemove = shallowRef<Resource[]>([]);
    const memo = ref<string | null>(null);
    const color = ref<string | null>(null);
    const subject = ref<string | null>(null);
    const frame = ref<string | null>(null);

    const validationErrors = computed(() => {
      const ret: string[] = [];
      if(
        sourceEventsIncludesLesson.value &&
        timeChangeMode.value === 'timeshift'
      ) ret.push('timechangemode-incompatible');
      if(
        sourceEventsIncludesLesson.value &&
        resourceChangeMode.value === 'general'
      ) ret.push('resourcechangemode-incompatible');
      if(subject.value == '') ret.push('subject-empty');
      return ret;
    });

    const defaultColor = computed(
      () => colorLabels.value[0]?.color ?? '#FFFFFF'
    );

    const submit = handleError(async () => {
      if(validationErrors.value.length) return;
      await eventStore.mutate(props.sourceEvents.map(x => {
        const ret = { ...eventToEventInput(x), id: x.id };
        if(dateShift.value) {
          ret.startTime = add(
            x.startTime, timedelta({ days: dateShift.value })
          );
          ret.endTime = add(
            x.endTime, timedelta({ days: dateShift.value })
          );
        }
        if(timeChangeMode.value === 'timelabelset') {
          if(timeLabel.value != null) {
            ret.startTime = DateTime.combine(
              ret.startTime.date(), timeLabel.value.startTime
            );
            ret.endTime = DateTime.combine(
              ret.startTime.date(), timeLabel.value.endTime
            );
          }
          ret.timeLabel = timeLabel.value?.id ?? null;
        } else if(timeChangeMode.value === 'timeshift') {
          if(timeShift.value) {
            ret.startTime = add(
              x.startTime, timedelta({ minutes: timeShift.value })
            );
            ret.endTime = add(
              x.endTime, timedelta({ minutes: timeShift.value })
            );
          }
          ret.timeLabel = null;
        }
        if(resourceChangeMode.value === 'lesson') {
          if(teacher.value != null) {
            ret.resources = [
              ...x.resources.filter(r => r.type !== 'teacher'), teacher.value,
            ].map(r => r.id);
          }
          if(student.value != null) {
            ret.resources = [
              ...x.resources.filter(r => r.type !== 'student'), student.value,
            ].map(r => r.id);
          }
        } else if(resourceChangeMode.value === 'general') {
          const resourceIDsToRemove = resourcesToRemove.value.map(x => x.id);
          ret.resources = [...x.resources.filter(
            r => !resourceIDsToRemove.includes(r.id)
          ), ...resourcesToAdd.value].map(r => r.id);
        }
        if(memo.value != null) ret.memo = memo.value;
        if(color.value != null) ret.color = color.value;
        if(ret.type === 'lesson') {
          if(subject.value != null) ret.subject = subject.value;
          if(frame.value != null) ret.frame = frame.value;
        }
        return ret;
      }).map(x => ({ opcode: 'update_event', param: x })));
      emit('run');
    });

    return {
      resources: resourceStore.resources, getResourceDisplayText,
      sourceEventsIncludesLesson, dateShift,
      timeChangeMode, timeShift, timeLabel, resourceChangeMode,
      teacher, student, resourcesToAdd, resourcesToRemove,
      memo, color, subject, frame, validationErrors, defaultColor, submit,
    };
  },
}
</script>

<template>
<h1>変更</h1>
<p>選択したイベントにまとめて変更を適用します。</p>
<form @submit.prevent="submit()">
  <details>
    <summary>日付{{ dateShift === 0 ? '' : '📝' }}</summary>
    <p>
      <label>変化量: <input-integer v-model="dateShift" />日</label>
    </p>
    <p>
      <output>
        {{
          dateShift === 0 ? '変更なし' : `${Math.abs(dateShift)}日${
            dateShift > 0 ? '後' : '前'
          }にずらす`
        }}
      </output>
    </p>
  </details>
  <details>
    <summary>
      時刻{{ timeChangeMode === 'nochange' ? '' : '📝' }}
    </summary>
    <p>
      <label>
        <input
          type="radio" v-model="timeChangeMode" value="nochange"
          name="timeChangeMode"
        />変更なし
      </label>
      <label>
        <input
          type="radio" v-model="timeChangeMode" value="timelabelset"
          name="timeChangeMode"
        />時間帯指定
      </label>
      <label>
        <input
          type="radio" v-model="timeChangeMode" value="timeshift"
          name="timeChangeMode"
        />時刻ずらし
      </label>
    </p>
    <p v-if="timeChangeMode === 'timelabelset'">
      <label>
        時間帯:
        <input-time-label v-model="timeLabel" no-selection-text="[指定なし]" />
      </label>
    </p>
    <template v-else-if="timeChangeMode === 'timeshift'">
      <p v-if="sourceEventsIncludesLesson">
        選択されたイベントに種別が授業のものが含まれているため、この設定は使用できません。
      </p>
      <template v-else>
        <p>時間帯ラベルは無指定に変更されます。</p>
        <p><label>変化量: <input-integer v-model="timeShift" />分</label></p>
        <p>
          <output>
            {{
              timeShift === 0 ? '時刻変更なし' : `${(hour => hour ? `${hour}時間` : '')(
                Math.floor(Math.abs(timeShift) / 60)
              )}${Math.abs(timeShift) % 60}分${timeShift > 0 ? '後' : '前'}にずらす`
            }}
          </output>
        </p>
      </template>
    </template>
  </details>
  <details>
    <summary>
      リソース{{ resourceChangeMode === 'nochange' ? '' : '📝' }}
    </summary>
    <p>
      <label>
        <input
          type="radio" v-model="resourceChangeMode" value="nochange"
          name="resourceChangeMode"
        />変更なし
      </label>
      <label>
        <input
          type="radio" v-model="resourceChangeMode" value="lesson"
          name="resourceChangeMode"
        />授業用
      </label>
      <label>
        <input
          type="radio" v-model="resourceChangeMode" value="general"
          name="resourceChangeMode"
        />詳細
      </label>
    </p>
    <template v-if="resourceChangeMode === 'lesson'">
      <p>講師と生徒を一人ずつ設定します。</p>
      <p>
        <label>
          講師:
          <select v-model="teacher">
            <option :value="null">[変更なし]</option>
            <option v-for="resource of resources.filter(
              x => !x.disabled && x.type === 'teacher'
            )" :key="resource.id" :value="resource">
              {{ getResourceDisplayText(resource) }}
            </option>
          </select>
        </label>
      </p>
      <p>
        <label>
          生徒:
          <select v-model="student">
            <option :value="null">[変更なし]</option>
            <option v-for="resource of resources.filter(
              x => !x.disabled && x.type === 'student'
            )" :key="resource.id" :value="resource">
              {{ getResourceDisplayText(resource) }}
            </option>
          </select>
        </label>
      </p>
    </template>
    <template v-else-if="resourceChangeMode === 'general'">
      <p v-if="sourceEventsIncludesLesson">
        選択されたイベントに種別が授業のものが含まれているため、この設定は使用できません。
      </p>
      <template v-else>
        <label>
          追加するリソース
          <input-resource-multi-select
            v-model="resourcesToAdd"
            :options="resources.filter(
              x => !x.disabled && ['teacher', 'student'].includes(x.type)
            )"
          />
        </label>
        <label>
          削除するリソース
          <input-resource-multi-select
            v-model="resourcesToRemove"
            :options="resources.filter(
              x => !x.disabled && ['teacher', 'student'].includes(x.type)
            )"
          />
        </label>
      </template>
    </template>
  </details>
  <details>
    <summary>メモ{{ memo == null ? '' : '📝' }}</summary>
    <p>
      <label>
        <input type="checkbox" :checked="memo != null" @input="
          memo = ($event.target as HTMLInputElement).checked ? '' : null
        " /> 変更する
      </label>
      <input v-if="memo != null" v-model="memo" />
    </p>
  </details>
  <details>
    <summary>色{{ color == null ? '' : '📝' }}</summary>
    <p>
      <label>
        <input type="checkbox" :checked="color != null" @input="
          color = ($event.target as HTMLInputElement).checked ? defaultColor : null
        " /> 変更する
      </label>
      <input-event-color v-if="color != null" v-model="color" />
    </p>
  </details>
  <details>
    <summary>教科{{ subject == null ? '' : '📝' }}</summary>
    <p>授業以外の種別のイベントには効果がありません。</p>
    <p>
      <label>
        <input type="checkbox" :checked="subject != null" @input="
          subject = ($event.target as HTMLInputElement).checked ? '' : null
        " /> 変更する
      </label>
      <input v-if="subject != null" v-model="subject" />
    </p>
  </details>
  <details>
    <summary>枠{{ frame == null ? '' : '📝' }}</summary>
    <p>授業以外の種別のイベントには効果がありません。</p>
    <p>
      <label>
        <input type="checkbox" :checked="frame != null" @input="
          frame = ($event.target as HTMLInputElement).checked ? '' : null
        " /> 変更する
      </label>
      <input v-if="frame != null" v-model="frame" />
    </p>
  </details>
  <ul>
    <li v-for="errorCode of validationErrors" :key="errorCode">
      {{
        {
          'subject-empty': '教科が空です',
          'timechangemode-incompatible': '時刻の変更欄にエラーがあります',
          'resourcechangemode-incompatible': 'リソースの変更欄にエラーがあります',
        }[errorCode]
      }}
    </li>
  </ul>
  <button :disabled="validationErrors.length > 0">変更を適用</button>
</form>
</template>
