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

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


export type ModelValuePropType = {
  readonly resources: readonly Resource[], readonly startTime: DateTime,
  readonly endTime: DateTime, readonly timeLabel: TimeLabel | null,
  readonly color: string, readonly memo: string,
} & ({ readonly type: 'standard' } | {
  readonly type: 'lesson', readonly subject: string, readonly frame: string,
});

export default {
  name: 'InputEvent',
  components: {
    InputResourceMultiSelect, InputEventTime, InputCourseDate, InputTimeLabel,
    InputEventColor,
  },
  props: {
    modelValue: { type: Object as PropType<{
      readonly resources: readonly Resource[], readonly startTime: DateTime,
      readonly endTime: DateTime, readonly timeLabel: TimeLabel | null,
      readonly color: string, readonly memo: string,
    } & ({ readonly type: 'standard' } | {
      readonly type: 'lesson', subject: string, readonly frame: string,
    })>, required: true },
    invalid: { type: Boolean, required: true },
  },
  emits: ['update:modelValue', 'update:invalid'],
  setup(props, { emit }) {
    const today = Date.today();
    const resourceStore = inject(injectionKeys.resourceStore);
    const resources = resourceStore.resources;

    const event = shallowReactive<{
      type: 'standard' | 'lesson', resources: Resource[],
      classroom: string | null, teacher: string | null, student: string | null,
      date: Date | null, timeLabel: TimeLabel | null,
      color: string, memo: string, subject: string, frame: string,
    }>({
      type: 'standard', resources: [], classroom: null,
      teacher: null, student: null, date: null, timeLabel: null,
      color: '#FFFFFF', memo: '', subject: '', frame: '',
    });
    const eventTime = shallowRef<{
      startTime: DateTime, endTime: DateTime, timeLabel: TimeLabel | null,
    }>({
      startTime: DateTime.combine(today, new Time()),
      endTime: DateTime.combine(
        add(today, timedelta({ days: 1 })), new Time()
      ), timeLabel: null,
    });
    const eventTimeInputInvalid = ref(false);

    let lastEmittedModelValue: typeof props.modelValue | null = null;

    watch(() => props.modelValue, () => {
      if(toRaw(props.modelValue) === lastEmittedModelValue) return;
      event.type = props.modelValue.type;
      event.classroom = props.modelValue.resources.find(
        x => x.type === 'classroom'
      )?.id ?? null;
      event.resources = props.modelValue.resources.filter(
        x => x.type !== 'classroom'
      );
      const teachers = props.modelValue.resources.filter(
        x => x.type === 'teacher'
      );
      event.teacher = teachers.length === 1 ? teachers[0].id : null;
      const students = props.modelValue.resources.filter(
        x => x.type === 'student'
      );
      event.student = students.length === 1 ? students[0].id : null;
      event.date = props.modelValue.startTime.date();
      event.timeLabel = props.modelValue.timeLabel;
      eventTime.value = {
        startTime: props.modelValue.startTime,
        endTime: props.modelValue.endTime,
        timeLabel: props.modelValue.timeLabel,
      };
      event.color = props.modelValue.color;
      event.memo = props.modelValue.memo;
      event.subject = (
        props.modelValue.type === 'lesson' ? props.modelValue.subject : ''
      );
      event.frame = (
        props.modelValue.type === 'lesson' ? props.modelValue.frame : ''
      );
    }, { immediate: true });

    const eventInvalidity = computed(() => {
      const errors: string[] = [];
      if(event.classroom == null) {
        errors.push('classroom-null');
      }
      if(event.type === 'lesson') {
        if(event.teacher == null) {
          errors.push('teacher-null');
        }
        if(event.student == null) {
          errors.push('student-null');
        }
        if(!event.date) {
          errors.push('date-null');
        }
        if(!event.timeLabel) {
          errors.push('timelabel-null');
        }
        if(!event.subject) {
          errors.push('subject-empty');
        }
      } else {
        if(eventTimeInputInvalid.value) {
          errors.push('time-invalid');
        }
      }
      return errors;
    });

    const modelValue = computed<typeof props.modelValue | null>(() => {
      if(eventInvalidity.value.length) return null;
      return {
        resources: [
          resources.value.find(r => r.id === event.classroom)!,
          ...event.type === 'lesson' ? [event.teacher!, event.student!].map(
            x => resources.value.find(r => r.id === x)!
          ) : event.resources
        ],
        memo: event.memo,
        color: event.color,
        ... event.type === 'lesson' ? {
          type: 'lesson',
          startTime: DateTime.combine(event.date!, event.timeLabel!.startTime),
          endTime: DateTime.combine(event.date!, event.timeLabel!.endTime),
          timeLabel: event.timeLabel,
          subject: event.subject, frame: event.frame,
        } : {
          type: 'standard',
          startTime: eventTime.value.startTime,
          endTime: eventTime.value.endTime,
          timeLabel: eventTime.value.timeLabel,
        },
      };
    });

    watch(modelValue, () => {
      if(!modelValue.value) return;
      lastEmittedModelValue = modelValue.value;
      emit('update:modelValue', modelValue.value);
    });

    watch(eventInvalidity, () => {
      emit('update:invalid', eventInvalidity.value.length > 0)
    }, { immediate: true });

    return {
      resources, getResourceDisplayText, event, eventTime, eventInvalidity,
      eventTimeInputInvalid,
    };
  },
}
</script>

<template>
<fieldset>
  <legend>種別</legend>
  <label>
    <input
      type="radio" v-model="event.type" name="eventType" value="standard"
    /> 標準
  </label>
  <label>
    <input
      type="radio" v-model="event.type" name="eventType" value="lesson"
    /> 授業
  </label>
</fieldset>
<fieldset>
  <legend>リソース</legend>
  <label>
    教室
    <select v-model="event.classroom">
      <option :value="null">[未指定]</option>
      <option
        v-for="r of resources.filter(x => x.type === 'classroom')"
        :key="r.id" :value="r.id"
      >{{ getResourceDisplayText(r) }}</option>
    </select>
  </label>
  <template v-if="event.type === 'lesson'">
    <label>
      講師
      <select v-model="event.teacher">
        <option
          v-for="r of resources.filter(x => x.type === 'teacher')"
          :key="r.id" :value="r.id"
        >{{ getResourceDisplayText(r) }}</option>
      </select>
    </label>
    <label>
      生徒
      <select v-model="event.student">
        <option
          v-for="r of resources.filter(x => x.type === 'student')"
          :key="r.id" :value="r.id"
        >{{ getResourceDisplayText(r) }}</option>
      </select>
    </label>
  </template>
  <div v-else>
    <label>
      講師・生徒
      <input-resource-multi-select
        v-model="event.resources" :options="resources.filter(
          x => ['teacher', 'student'].includes(x.type)
        )"
      />
    </label>
  </div>
</fieldset>
<fieldset>
  <legend>時刻</legend>
  <template v-if="event.type !== 'lesson'">
    <InputEventTime
      v-model="eventTime" v-model:invalid="eventTimeInputInvalid"
    />
  </template>
  <template v-else>
    <label>日付 <InputCourseDate v-model="event.date" /></label>
    <label>時間帯 <InputTimeLabel v-model="event.timeLabel" /></label>
  </template>
</fieldset>
<label>メモ <input v-model="event.memo" /></label>
<label>色 <InputEventColor v-model="event.color" /></label>
<template v-if="event.type === 'lesson'">
  <label>教科 <input v-model="event.subject" /></label>
  <label>枠 <input v-model="event.frame" /></label>
</template>
<ul>
  <li v-for="error of eventInvalidity" :key="error">
    {{ {
      'classroom-null': '教室が指定されていません',
      'teacher-null': '講師が指定されていません',
      'student-null': '生徒が指定されていません',
      'date-null': '日付が指定されていません',
      'timelabel-null': '時間帯が指定されていません',
      'time-invalid': '時刻入力欄にエラーがあります',
      'subject-empty': '教科が空です',
    }[error] }}
  </li>
</ul>
</template>
