<script>
import { ref, computed } from 'vue';
import { parse as csvParse } from '@vanillaes/csv';

import { inject, keys as injectionKeys } from '../../../injection';
import { comparerByKey, readTextFile } from '../../../common/utils.js';


export default {
  name: 'PageMasterConfigTeacher',
  setup() {
    const notification = inject(injectionKeys.notification);
    const handleError = inject(injectionKeys.errorHandler).handleErrorAsync;
    const resourceStore = inject(injectionKeys.resourceStore);

    const resources = ref(/** @type {{
      id: string | null, firstName: string, lastName: string,
      firstNameKana: string, lastNameKana: string,
      disabled: boolean, deleted: boolean,
    }[]} */([]));
    const resourceErrors = computed(() => {
      const notDeletedItems = resources.value.filter(x => !x.deleted);
      const ret = [];
      ret.push(...notDeletedItems.filter(x => !x.firstName).map(x => ({
        item: x, code: 'novalue', property: 'firstName'
      })));
      ret.push(...notDeletedItems.filter(x => !x.lastName).map(x => ({
        item: x, code: 'novalue', property: 'lastName'
      })));
      ret.push(...notDeletedItems.filter(x => !x.firstNameKana).map(x => ({
        item: x, code: 'novalue', property: 'firstNameKana'
      })));
      ret.push(...notDeletedItems.filter(x => !x.lastNameKana).map(x => ({
        item: x, code: 'novalue', property: 'lastNameKana'
      })));
      ret.push(...notDeletedItems.filter(
        x => !/^[\x00-\x7F゠-ヿ]*$/u.test(x.firstNameKana)
      ).map(x => ({ item: x, code: 'nonkana', property: 'firstNameKana' })));
      ret.push(...notDeletedItems.filter(
        x => !/^[\x00-\x7F゠-ヿ]*$/u.test(x.lastNameKana)
      ).map(x => ({ item: x, code: 'nonkana', property: 'lastNameKana' })));
      return ret;
    });

    const load = handleError(async () => {
      await resourceStore.load();
      resources.value = resourceStore.resources.value.filter(
        x => x.type === 'teacher'
      ).map(x => ({
        id: x.id, firstName: x.firstName, lastName: x.lastName,
        firstNameKana: x.firstNameKana, lastNameKana: x.lastNameKana,
        disabled: x.disabled, deleted: false,
      }));
      sort();
    });
    load();

    function add() {
      resources.value.push({
        id: null, firstName: '', lastName: '',
        firstNameKana: '', lastNameKana: '', disabled: false,
        deleted: false,
      });
    }

    function sort() {
      resources.value.sort(comparerByKey(x => [
        x.lastNameKana, x.firstNameKana
      ]));
    }

    const save = handleError(async () => {
      if(resourceErrors.value.length) {
        notification.add('error', '入力欄にエラーがあります。修正してください。');
        return;
      }

      const toAddItems = resources.value.filter(
        x => x.id == null && !x.deleted
      );
      const toUpdateItems = resources.value.filter(
        x => x.id != null && !x.deleted
      );
      const toRemoveItems = resources.value.filter(
        x => x.id != null && x.deleted
      );

      if(toRemoveItems.length) {
        if(!confirm('いくつかの講師が削除されます。削除する講師が指定されたイベントがある場合、それらのイベントからその講師の指定が消えます。本当に削除しますか？')) {
          return;
        }
      }

      await resourceStore.mutate(toAddItems.map(x => ({
        opcode: 'add_resource', param: {
          multiplicity: 1, disabled: x.disabled, type: 'teacher',
          firstName: x.firstName, lastName: x.lastName,
          firstNameKana: x.firstNameKana, lastNameKana: x.lastNameKana,
        },
      })).concat(toUpdateItems.map(x => ({
        opcode: 'update_resource', param: {
          id: x.id, multiplicity: 1, disabled: x.disabled, type: 'teacher',
          firstName: x.firstName, lastName: x.lastName,
          firstNameKana: x.firstNameKana, lastNameKana: x.lastNameKana,
        },
      })), toRemoveItems.map(x => ({
        opcode: 'remove_resource', param: { id: x.id },
      }))));

      notification.add('info', '保存しました。');

      await load();
    });

    const readFromCSV = handleError(async file => {
      const text = await readTextFile(file);
      const records = csvParse(text);
      if(records.some(x => x.length !== 4)) {
        notification.add(
          'error', 'CSVファイルの形式が異なります。各行は姓,名,姓（カナ）,名（カナ）の4フィールドです。'
        );
        return;
      }
      await load();

      const existingIds = records.map(record => resources.value.find(x => (
        x.lastName === record[0] && x.firstName === record[1] &&
        x.lastNameKana === record[2] && x.firstNameKana === record[3]
      ))?.id ?? null);
      for(const resource of resources.value) {
        if(!existingIds.includes(resource.id)) {
          resource.deleted = true;
        }
      }
      resources.value.push(...records.filter(
        (x, i) => existingIds[i] == null
      ).map(x => ({
        id: null, lastName: x[0], firstName: x[1], lastNameKana: x[2],
        firstNameKana: x[3], disabled: false, deleted: false,
      })));
    });

    return {
      resources, resourceErrors, load, add, sort, save, readFromCSV,
    };
  }
}
</script>

<template>
  <h1>講師登録</h1>
  <p>「変更を適用」ボタンを押さない限り変更は保存されません！</p>
  <details>
    <summary>CSVファイルから読み込み</summary>
    <label>
      ファイル選択：
      <input type="file" accept="text/csv" @change="
        readFromCSV($event.target.files[0]); $event.target.value = '';
      " />
    </label>
    <p>各行は<code>姓,名,姓（カナ）,名（カナ）</code>の形式です。読み込む際は事前にこのページ上の保存されていない変更が全てリセットされます。</p>
  </details>
  <table>
    <thead>
      <tr>
        <th>ID</th><th>変更状況</th><th>姓</th><th>名</th>
        <th>姓（カナ）</th><th>名（カナ）</th><th>非表示</th>
      </tr>
    </thead>
    <tbody>
      <template v-for="x, idx of resources" :key="x.id">
        <tr v-if="!x.deleted, true">
          <th :title="x.id">
            {{ x.id != null ? `...${x.id.slice(-4)}` : '[未割当]' }}
          </th>
          <td>
            {{ x.deleted ? '削除✘' : x.id == null ? '新規✧' : '維持✔' }}
            <button v-if="x.id == null" type="button" @click="
              resources.splice(idx, 1);
            ">削除</button>
            <button v-else type="button" @click="x.deleted = !x.deleted;">
              {{ x.deleted ? '削除しない' : '削除' }}
            </button>
          </td>
          <td><input v-model="x.lastName" /></td>
          <td><input v-model="x.firstName" /></td>
          <td><input v-model="x.lastNameKana" /></td>
          <td><input v-model="x.firstNameKana" /></td>
          <td><input type="checkbox" v-model="x.disabled" /></td>
        </tr>
      </template>
    </tbody>
  </table>

  <button type="button" @click="add()">追加</button>
  <button type="button" @click="sort()">ソート</button>

  <ul>
    <li v-for="error, idx of resourceErrors" :key="idx">
      {{
        `${resources.indexOf(error.item) + 1}番目の${{
          firstName: '名', lastName: '姓',
          firstNameKana: '名（カナ）', lastNameKana: '姓（カナ）',
        }[error.property]}${{
          novalue: 'が指定されていません', nonkana: 'にカタカナ以外が含まれています',
        }[error.code]}`
      }}
    </li>
  </ul>

  <p><button type="button" @click="save()">変更を適用</button></p>
  <!-- <p><button type="button" @click="load()">リセット</button></p> -->
</template>
