<template>
  <div class="q-pa-md">
    <div class="q-gutter-sm row items-start">
        <q-breadcrumbs>
          <q-breadcrumbs-el icon="domain" label="接続先管理" />
        </q-breadcrumbs>
    </div>
    <q-table :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination">

      <template v-slot:top>
        <q-btn v-permissions="Actions.domain.add" color="primary" :disable="loading" label="新規" @click="addRow" />
        <q-space />
        <q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索">
          <template v-slot:append>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>

      <template v-slot:header-cell-active="p">
        <q-th auto-width :props="p">
          <q-select class="filter-header" v-model="activeFilter" :options="activeOptions" @update:model-value="activeFilterUpdate" borderless
            dense options-dense hide-bottom-space/>
        </q-th>
      </template>

      <template v-slot:body-cell-active="p">
        <q-td auto-width :props="p">
          <q-badge v-if="!p.row.domainActive" color="grey">未使用</q-badge>
          <q-badge v-if="p.row.id == currentDomainId" color="primary">既定</q-badge>
        </q-td>
      </template>

      <template v-slot:body-cell-owner="p">
        <q-td auto-width :props="p">
          <q-badge v-if="isOwner(p.row)" color="purple">自分</q-badge>
          <span v-else>{{ p.row.owner.fullName }}</span>
        </q-td>
      </template>

      <template v-slot:body-cell-actions="p">
        <q-td :props="p">
            <table-action-menu :row="p.row" :actions="actionList" />
        </q-td>
      </template>

    </q-table>

    <q-dialog :model-value="show" persistent>
      <q-card style="min-width: 36em">
        <q-form class="q-gutter-md" @submit="onSubmit" autocomplete="off">
          <q-card-section>
            <div class="text-h6 q-ma-sm">Kintone Account</div>
          </q-card-section>

          <q-card-section class="q-py-none q-mt-none">
            <div class="q-gutter-lg">

              <q-input filled v-model="name" label="環境名 *" hint="kintoneの環境名を入力してください" lazy-rules
                :rules="[val => val && val.length > 0 || 'kintoneの環境名を入力してください。']" />

              <q-input filled v-model.trim="url" :readonly="!isCreate" label="Kintone url" :hint="isCreate ? 'KintoneのURLを入力してください':'KintoneのURLは変更できません。新規作成してください。'" lazy-rules
                :rules="[val => val && val.length > 0 || 'KintoneのURLを入力してください']" />

              <q-input v-if="isCreate" filled v-model="kintoneuser" label="ログイン名 *" hint="Kintoneのログイン名を入力してください" lazy-rules
                :rules="[val => val && val.length > 0 || 'Kintoneのログイン名を入力してください']" autocomplete="new-password" />

              <q-input v-if="isCreate" v-model="kintonepwd" filled :type="isPwd ? 'password' : 'text'"
                hint="Kintoneのパスワードを入力してください" label="パスワード" :disable="!isCreate" lazy-rules
                :rules="[val => val && val.length > 0 || 'Kintoneのパスワードを入力してください']" autocomplete="new-password">
                <template v-slot:append>
                  <q-icon :name="isPwd ? 'visibility_off' : 'visibility'" class="cursor-pointer"
                    @click="isPwd = !isPwd" />
                </template>
              </q-input>

              <q-item tag="label" class="q-pl-sm q-pr-none q-py-xs">
                  <q-item-section>
                    <q-item-label>接続先の有効化</q-item-label>
                  </q-item-section>
                  <q-item-section avatar>
                    <q-toggle v-model="domainActive" />
                  </q-item-section>
                </q-item>

              <div class="q-gutter-y-md" v-if="!isCreate">
                <q-separator />

                <q-item tag="label" class="q-pl-sm q-pr-none q-py-xs">
                  <q-item-section>
                    <q-item-label>管理者アカウントの変更</q-item-label>
                  </q-item-section>
                  <q-item-section avatar>
                    <q-toggle v-model="changeAccount" @update:model-value="updateChangeAccount" />
                  </q-item-section>
                </q-item>

                <q-expansion-item
                  header-class="hidden"
                  class="q-mt-none"
                  v-model="changeAccount"
                >
                    <q-input filled v-model="kintoneuser" label="ログイン名 *" hint="Kintoneのログイン名を入力してください" :disable="!changeAccount"
                    :rules="[val => val && val.length > 0 || 'Kintoneのログイン名を入力してください']" lazy-rules class="q-mt-md"/>

                    <q-input v-model="kintonepwd" filled :type="isPwd ? 'password' : 'text'" hint="Kintoneのパスワードを入力してください"
                      label="パスワード" :disable="!changeAccount"  lazy-rules class="q-mt-lg q-mb-md"
                      :rules="[val => val && val.length > 0 || 'Kintoneのパスワードを入力してください']" autocomplete="new-password">
                      <template v-slot:append>
                        <q-icon :name="isPwd ? 'visibility_off' : 'visibility'" class="cursor-pointer"
                          @click="isPwd = !isPwd" />
                      </template>
                    </q-input>
                  <!-- <q-btn label="asdf"/> -->
                </q-expansion-item>


              </div>
            </div>

          </q-card-section>

          <div class="q-mt-none">
            <q-banner dense :class="['text-white q-mt-sm q-py-xs q-mx-md', testResult?.success ? 'bg-green':'bg-red', testResult?.msg ? '':'invisible']">
              {{ testResult?.msg }}
            </q-banner>
            <q-card-actions class="text-primary q-mb-md q-mx-sm relative-position">
              <q-btn v-if="isCreate || changeAccount" :disable="!isConnectable" :loading="!!connectLoading" padding="xs md" :label="!!connectLoading ? '確認中...' : '接続確認'"
              color="primary" outline @click="tryConnect()"/>
              <q-btn v-if="!!connectLoading" label="停止" color="negative" flat class="q-ml-sm" @click="stopConnect" />
              <q-space />
              <q-btn :loading="addEditLoading" padding="xs md" label="保存" type="submit" color="primary" />
              <q-btn label="キャンセル" type="cancel" color="primary" flat class="q-ml-sm" @click="closeDg()" />
            </q-card-actions>
            </div>
        </q-form>
      </q-card>

    </q-dialog>

    <q-dialog v-model="confirm" persistent>
      <q-card>
        <!-- -1 loading -->
        <q-card-section v-if="deleteLoadingState == -1" class="row items-center">
          <q-spinner color="primary" size="2em"/>
          <span class="q-ml-sm">接続先利用権限を確認中</span>
        </q-card-section>
        <!-- > 0 can't delete -->
        <q-card-section v-else-if="deleteLoadingState > 0" class="row items-center">
          <q-icon name="error" color="negative" size="2em" />
          <span class="q-ml-sm">接続先は使用中です。削除してもよろしいですか？</span>
        </q-card-section>
        <!-- 0/-2 can delete -->
        <q-card-section v-else class="row items-center">
          <q-icon name="warning" color="warning" size="2em" />
          <span class="q-ml-sm">削除してもよろしいですか？</span>
        </q-card-section>

        <q-card-actions align="right">
          <q-btn flat label="キャンセル" color="primary" v-close-popup />
          <!-- > 0 can't delete -->
          <q-btn v-if="deleteLoadingState > 0" label="実行" color="primary" v-close-popup @click="openShareDg(SHARE_USE, editId)" />
          <!-- 0/-2 can delete -->
          <q-btn flat v-else label="OK" :disabled="deleteLoadingState == -1" :loading="deleteLoadingState == -2" color="primary" @click="deleteDomain()" />
        </q-card-actions>
      </q-card>
    </q-dialog>

    <share-usage-dialog v-model="shareDg" :domain="shareDomain" @close="shareDg = false" />
    <share-manage-dialog v-model="shareManageDg" :domain="shareDomain" @close="shareManageDg = false" />

  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { api } from 'boot/axios';
import { Actions } from 'boot/permissions';
import { useAuthStore } from 'stores/useAuthStore';
import ShareUsageDialog from 'components/ShareDomain/ShareUsageDialog.vue';
import ShareManageDialog from 'components/ShareDomain/ShareManageDialog.vue';
import TableActionMenu from 'components/TableActionMenu.vue';
import { IDomain, IDomainDisplay, IDomainOwnerDisplay, IDomainSubmit } from '../types/DomainTypes';

const authStore = useAuthStore();
const inactiveRowClass = (row: IDomainOwnerDisplay) => row.domainActive ? '' : 'inactive-row';

const columns = [
  { name: 'id', label: 'ID', field: 'id', align: 'left', sortable: true, classes: inactiveRowClass },
  // {
  //   name: 'tenantid',
  //   required: true,
  //   label: 'テナントID',
  //   field: 'tenantid',
  //   align: 'left',
  //   sortable: true,
  //   classes: inactiveRowClass
  // },
  { name: 'name', label: '環境名', field: 'name', align: 'left', sortable: true, classes: inactiveRowClass },
  { name: 'active', label: '', align: 'left', field: 'domainActive', classes: inactiveRowClass },
  { name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true, classes: inactiveRowClass },
  { name: 'user', label: 'ログイン名', field: 'user', align: 'left', classes: inactiveRowClass },
  { name: 'owner', label: '所有者', field: '', align: 'left', classes: inactiveRowClass },
  { name: 'actions', label: '', field: 'actions', classes: inactiveRowClass }
];

const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
const loading = ref(false);
const addEditLoading = ref(false);
const deleteLoadingState = ref<number>(-1); // -2: deleteLoading, -1: loading, 0: allow, > 0: user count
const connectLoading = ref<AbortController|null>(null);

const filter = ref('');
const rows = ref<IDomainOwnerDisplay[]>([]);
const show = ref(false);
const confirm = ref(false);
const changeAccount = ref(false);
const testResult = ref<{msg: string, success?: boolean}|null>(null);

const currentDomainId = computed(() => authStore.currentDomain.id);
// const tenantid = ref(authStore.currentDomain.id);
const name = ref('');
const url = ref('');
const isPwd = ref(true);
const kintoneuser = ref('');
const kintoneuserBK = ref('');
const kintonepwd = ref('');
const domainActive = ref(true);
const isCreate = ref(true);
let editId = ref(0);
const shareDg = ref(false);
const shareManageDg = ref(false);
const shareDomain = ref<IDomainOwnerDisplay>({} as IDomainOwnerDisplay);

const activeOptions = [
  { value: 0, label: 'すべて' },
  { value: 1, label: '使用' },
  { value: 2, label: '未使用'}
]
const activeFilter = ref(activeOptions[0]);

const activeFilterUpdate = (option: {value: number}) => {
  switch (option.value) {
    case 1:
      getDomain((row) => row.domainActive)
      break;
    case 2:
      getDomain((row) => !row.domainActive)
      break;
    default:
      getDomain()
      break;
  }
}

const SHARE_USE = 'use';
const SHARE_MANAGE = 'manage';

const actionList =  [
  { label: '編集', icon: 'edit_note', permission: Actions.domain.edit, action: editRow },
  { label: '利用権限設定', icon: 'person_add_alt', permission: Actions.domain.grantUse,
    action: (row: IDomainOwnerDisplay) => {openShareDg(SHARE_USE, row)} },
  { label: '管理権限設定', icon: 'add_moderator', permission: Actions.domain.grantManage,
    disable: (row: IDomainOwnerDisplay) => !isOwner(row),
    tooltip: (row: IDomainOwnerDisplay) => isOwner(row) ? '' : '接続先の所有者でないため、操作できません',
    action: (row: IDomainOwnerDisplay) => {openShareDg(SHARE_MANAGE, row)}
  },
  { separator: true },
  { label: '削除', icon: 'delete_outline', permission: Actions.domain.delete, class: 'text-red', action: removeRow },
];

const isOwner = (row: IDomainOwnerDisplay) => row.owner.id === Number(authStore.userId);

const getDomain = async (filter?: (row: IDomainOwnerDisplay) => boolean) => {
  loading.value = true;
  const { data } = await api.get<{data:IDomain[]}>('api/domains');
  rows.value = data.data.map((item) => {
    return {
      id: item.id,
      tenantid: item.tenantid,
      domainActive: item.is_active,
      name: item.name,
      url: item.url,
      user: item.kintoneuser,
      password: item.kintonepwd,
      owner: {
        id: item.owner.id,
        firstName: item.owner.first_name,
        lastName: item.owner.last_name,
        fullNameSearch: (item.owner.last_name + item.owner.first_name).toLowerCase(),
        fullName: item.owner.last_name + ' ' + item.owner.first_name,
        email: item.owner.email,
        isActive: item.owner.is_active,
        isSuperuser: item.owner.is_superuser,
      }
    }
  }).filter(filter || (() => true));
  loading.value = false;
}

onMounted(async () => {
  await getDomain();
})

// emulate fetching data from server
const addRow = () => {
  // editId.value
  onReset();
  show.value = true;
}

async function removeRow(row: IDomainOwnerDisplay) {
  confirm.value = true;
  deleteLoadingState.value = -1;
  editId.value = row.id;

  const { data } = await api.get(`/api/domainshareduser/${row.id}`);
  deleteLoadingState.value = data.data.length;
}

const deleteDomain = () => {
  deleteLoadingState.value = -2;
  api.delete(`api/domain/${editId.value}`).then(({ data }) => {
    if (!data.data) {
      // TODO dialog
    }
    confirm.value = false;
    deleteLoadingState.value = -1;
    getDomain();
    // authStore.setCurrentDomain();
  })
  editId.value = 0; // set in removeRow()
};

function editRow(row: any) {
  isCreate.value = false
  editId.value = row.id;
  // tenantid.value = row.tenantid;
  name.value = row.name;
  url.value = row.url;
  kintoneuser.value = row.user;
  kintoneuserBK.value = row.user;
  kintonepwd.value = ''
  domainActive.value = row.domainActive;
  isPwd.value = true;
  show.value = true;
};

const updateChangeAccount = () => {
  kintoneuser.value = kintoneuserBK.value;
  kintonepwd.value = ''
  connectLoading.value = null
  isPwd.value = true
  stopConnect();
  testResult.value = null;
}

const closeDg = () => {
  show.value = false;
  onReset();
}

const tryConnect = async (isTest = true) => {
  testResult.value = null;
  if (isTest) {
    connectLoading.value = new AbortController();
  }
  try {
    const { data }: {data: {code: string, groups: {code: string}[]}} = await api.get('api/v1/group', {
      params:{
        kintoneurl: ensureHttps(url.value),
        kintoneuser: kintoneuser.value,
        kintonepwd: kintonepwd.value,
      },
      signal: (isTest && connectLoading.value) ? connectLoading.value.signal : undefined
    });
    if (data.code === 'CB_WA01') {
      testResult.value = { msg: 'ユーザーのパスワード認証に失敗しました。' }
    } else if (data.groups && data.groups.some((group: {code: string}) => group.code === 'Administrators')){
      testResult.value = { success: true, msg: isTest ? 'kintoneの管理者アカウントで接続に成功しました。' : '' }
      return true;
    } else {
      testResult.value = { msg: 'このアカウントはkintoneの管理者アカウントではありません。' }
    }
    return false;
  } catch (e) {
    const error = e as { code?: string };
    if (error.code === 'ERR_CANCELED') {
      console.log('Aborted');
    } else {
      testResult.value = { msg: 'サーバーに接続できませんでした。' }
      throw error;
    }
    return false;
  } finally {
    connectLoading.value = null;
  }
}

const ensureHttps = (url: string) => {
    return !/^https?:\/\//i.test(url) ? 'https://' + url : url;
}

const stopConnect = () => {
  if (!connectLoading.value) return;
  connectLoading.value?.abort();
  connectLoading.value = null;
}

const onSubmit = async () => {
  addEditLoading.value = true;
  try {
    await tryConnect(false);
  } catch (e) {
    addEditLoading.value = false;
    return;
  }
  const method = editId.value !== 0 ? 'put' : 'post';
  const param: IDomainSubmit = {
    'id': editId.value,
    'tenantid': '1', // TODO: テナントIDを取得する
    'name': name.value,
    'url': url.value,
    'kintoneuser': kintoneuser.value,
    'kintonepwd': ((isCreate.value && editId.value == 0) || changeAccount.value) ? kintonepwd.value : '',
    'is_active': domainActive.value,
    'ownerid': authStore.userId || ''
  }
  // for search: api.put(`api/domain`)、api.post(`api/domain`)
  api[method].apply(api, ['api/domain', param]).then(async (resp: any) => {
      const res = resp.data;
      if (res.data.id === currentDomainId.value && !res.data.is_active) {
        await authStore.setCurrentDomain();
      }
      getDomain();
      closeDg();
      onReset();
      addEditLoading.value = false;
    })
}

function openShareDg(type: typeof SHARE_MANAGE|typeof SHARE_USE, row: IDomainOwnerDisplay|number) {
  if (typeof row === 'number') {
    row = rows.value.find(item => item.id === row) as IDomainOwnerDisplay;
  }
  shareDomain.value = row;
  if (type === SHARE_USE) {
    shareDg.value = true;
  } else if (type === SHARE_MANAGE) {
    shareManageDg.value = true;
  }
};

const isConnectable = computed(()=> {
  return url.value && kintoneuser.value && kintonepwd.value
})

const onReset = () => {
  name.value = '';
  url.value = '';
  kintoneuser.value = '';
  kintoneuserBK.value = '';
  kintonepwd.value = '';
  isPwd.value = true;
  editId.value = 0;
  isCreate.value = true;
  domainActive.value = true;
  changeAccount.value = false;
  addEditLoading.value = false;
  connectLoading.value = null
  testResult.value = null;
}
</script>
<style lang="scss">
.filter-header .q-field__native {
  font-size: 12px;
  font-weight: 500;
}
.filter-header .q-icon {
  width: 12px;
}
.q-table td.inactive-row {
  color: #aaa;
  background-color: #fafafa;
}
.q-table tr > td.inactive-row:last-child {
  color: inherit;
}
</style>
