<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { useTokenStore } from '@/stores/token';
import MessageBox from '@/components/MessageBox.vue';
import {
  isAdmin as apiProfileIsAdmin,
  changePassword as apiProfileChangePassword,
  getToken as apiProfileGetToken,
  deleteToken as apiProfileDeleteToken,
  type TokenRow,
} from '@/api/profile';
import {
  get as apiAdminGet,
  add as apiAdminAdd,
  update as apiAdminUpdate,
  del as apiAdminDel,
  type AdminUserRow,
} from '@/api/admin';
import TokenItem from '@/components/admin/TokenItem.vue';
import UserItem from '@/components/admin/UserItem.vue';
import { i18n } from '@/utils/i18n';

const token = useTokenStore();
const messagebox = ref<InstanceType<typeof MessageBox>>();

// tab control state
const activeTab = ref<number>(1);
const showUserTab = ref<boolean>(false);

// profile tab state
const profilePendingPassword = ref<string>("");

// token tab state
const tokenItems = ref<Map<string, TokenRow>>(new Map());

// user tab state
const userItems = ref<Map<string, AdminUserRow>>(new Map());
const pendingUsername = ref<string>("");

onMounted(async () => {
  // check admin status for user tab visibility
  showUserTab.value = await apiProfileIsAdmin(token.currentToken);
  // auto-refresh both lists
  await refreshTokenList();
  if (showUserTab.value) {
    await refreshUserList();
  }
})

// region: Profile Tab

const changePassword = async () => {
  const newpassword = profilePendingPassword.value;
  if (newpassword === "") return;

  const rv = await apiProfileChangePassword(token.currentToken, newpassword);
  if (rv) {
    messagebox.value?.show(i18n.global.t('js-success'));
    profilePendingPassword.value = "";
  } else {
    messagebox.value?.show(i18n.global.t('js-fail-update'));
  }
}

// endregion

// region: Token Tab

const refreshTokenList = async () => {
  // clean token items
  tokenItems.value.clear();

  // fetch data
  const rv = await apiProfileGetToken(token.currentToken);
  if (typeof rv === 'undefined') {
    console.error("fail to fetch token list");
    return;
  }

  // add into dict for rendering
  for (const item of rv) {
    tokenItems.value.set(item[1], item);
  }
}

const deleteTokenItem = async (uuid: string) => {
  const rv = await apiProfileDeleteToken(token.currentToken, uuid);
  if (!rv) {
    messagebox.value?.show(i18n.global.t('js-fail-delete'));
    return;
  }

  // TODO: revoking the current session token (the isMe case) is allowed here,
  // but the local tokenStore is not cleared afterwards. The client is left in
  // an inconsistent state until the next failed API call or page reload.
  // Faithfully preserved from legacy for now; revisit later.
  tokenItems.value.delete(uuid);
}

// endregion

// region: User List Tab

const refreshUserList = async () => {
  // clean user items
  userItems.value.clear();

  // fetch data
  const rv = await apiAdminGet(token.currentToken);
  if (typeof rv === 'undefined') {
    console.error("fail to fetch user list");
    return;
  }

  // add into dict for rendering
  for (const item of rv) {
    userItems.value.set(item[0], item);
  }
}

const addUser = async () => {
  const username = pendingUsername.value;
  if (username === "") return;

  const rv = await apiAdminAdd(token.currentToken, username);
  if (typeof rv === 'undefined') {
    messagebox.value?.show(i18n.global.t('js-fail-add'));
    return;
  }

  userItems.value.set(rv[0], rv);
}

const deleteUser = async (username: string) => {
  const rv = await apiAdminDel(token.currentToken, username);
  if (!rv) {
    messagebox.value?.show(i18n.global.t('js-fail-delete'));
    return;
  }

  userItems.value.delete(username);
}

const updateUser = async (username: string, newPassword: string, newIsAdmin: boolean) => {
  const savedIsAdmin = userItems.value.get(username)![1];
  const passwordArg = newPassword === "" ? undefined : newPassword;
  const isAdminArg = newIsAdmin === savedIsAdmin ? undefined : newIsAdmin;

  const rv = await apiAdminUpdate(token.currentToken, username, passwordArg, isAdminArg);
  if (!rv) {
    messagebox.value?.show(i18n.global.t('js-fail-update'));
    return;
  }

  // safely update data
  userItems.value.get(username)![1] = newIsAdmin;
}

// endregion

</script>

<template>
  <div class="container" style="margin-top: 20px;">
    <div class="tabs">
      <ul>
        <li :class="{ 'is-active': activeTab === 1 }" @click="activeTab = 1"><a>{{ $t('admin-tabcontrol-tabProfile') }}</a></li>
        <li :class="{ 'is-active': activeTab === 2 }" @click="activeTab = 2"><a>{{ $t('admin-tabcontrol-tabToken') }}</a></li>
        <li v-if="showUserTab" :class="{ 'is-active': activeTab === 3 }" @click="activeTab = 3"><a>{{ $t('admin-tabcontrol-tabUserList') }}</a></li>
      </ul>
    </div>
  </div>

  <div v-show="activeTab === 1" class="container" style="margin-top: 20px;">
    <h1 class="title">{{ $t('admin-changePassword') }}</h1>
    <div class="field has-addons">
      <div class="control">
        <input v-model="profilePendingPassword" class="input" type="password">
      </div>
      <div class="control" @click="changePassword">
        <a class="button is-primary">
          <span class="icon is-small"><font-awesome-icon icon="fas fa-key"></font-awesome-icon></span>
        </a>
      </div>
    </div>
  </div>

  <div v-show="activeTab === 2" class="container" style="margin-top: 20px;">
    <h1 class="title">{{ $t('admin-manageToken') }}</h1>
    <h2 class="subtitle">{{ $t('admin-manageToken-desc') }}</h2>
    <div class="control" @click="refreshTokenList">
      <a class="button is-primary">
        <span class="icon is-small"><font-awesome-icon icon="fas fa-sync"></font-awesome-icon></span>
      </a>
    </div>

    <div style="display: flex; flex-flow: column; margin-top: 1.25rem;">
      <div v-for="item in tokenItems.values()" :key="item[1]"
        style="display: flex; flex-flow: column; margin-top: 1.25rem;">
        <TokenItem :uuid="item[1]" :ua="item[3]" :ip="item[4]"
          :expire-on="new Date(item[2] * 1000).toLocaleString()" :is-me="token.currentToken === item[1]"
          @delete="deleteTokenItem" />
      </div>
    </div>
  </div>

  <div v-show="activeTab === 3" class="container" style="margin-top: 20px;">
    <h1 class="title">{{ $t('admin-userList') }}</h1>
    <div class="button-list">
      <div class="field has-addons">
        <div class="control">
          <input v-model="pendingUsername" class="input" type="text">
        </div>
        <div class="control" @click="addUser">
          <a class="button is-primary">
            <span class="icon is-small"><font-awesome-icon icon="fas fa-plus"></font-awesome-icon></span>
          </a>
        </div>
      </div>
      <div class="control" @click="refreshUserList">
        <a class="button is-primary">
          <span class="icon is-small"><font-awesome-icon icon="fas fa-sync"></font-awesome-icon></span>
        </a>
      </div>
    </div>

    <div style="display: flex; flex-flow: column; margin-top: 1.25rem;">
      <div v-for="item in userItems.values()" :key="item[0]"
        style="display: flex; flex-flow: column; margin-top: 1.25rem;">
        <UserItem :username="item[0]" :is-admin="item[1]" @delete="deleteUser" @update="updateUser" />
      </div>
    </div>
  </div>

  <MessageBox ref="messagebox" />
</template>

<style scoped></style>
