<script setup>

import { useI18n } from 'vue-i18n';
const i18n = useI18n();
const t = i18n.t;

import moment from 'moment-timezone';
import { ref, onMounted, computed, useTemplateRef } from 'vue';
import { Button, Menu, Dialog, InputDialog, FormGroup, Radiobutton, TableView, TextInput, InputGroup } from '@cloudron/pankow';
import { copyToClipboard, prettyLongDate } from '@cloudron/pankow/utils';
import { TOKEN_TYPES } from '../constants.js';
import Section from './Section.vue';
import TokensModel from '../models/TokensModel.js';

const tokensModel = TokensModel.create();

const apiTokens = ref([]);
const inputDialog = useTemplateRef('inputDialog');
const newDialog = useTemplateRef('newDialog');
const addedToken = ref('');
const tokenName = ref('');
const tokenScope = ref('rw');
const tokenAllowedIpRanges = ref('');
const tokenAllowedIpRangesError = ref('');
const columns = {
  name: {
    label: t('profile.apiTokens.name'),
    sort: true
  },
  lastUsedTime: {
    label: t('profile.apiTokens.lastUsed'),
    sort(a, b) {
      if (!a) return 1;
      if (!b) return -1;
      return moment(a).isBefore(b) ? 1 : -1;
    }
  },
  scope: {
    label: t('profile.apiTokens.scope'),
    hideMobile: true,
    sort: true
  },
  allowedIpRanges: {
    label: t('profile.apiTokens.allowedIpRanges'),
    hideMobile: true,
    sort: true
  },
  actions: {}
};

const actionMenuModel = ref([]);
const actionMenuElement = useTemplateRef('actionMenuElement');
function onActionMenu(apiToken, event) {
  actionMenuModel.value = [{
    icon: 'fa-solid fa-trash-alt',
    label: t('main.action.remove'),
    action: onRevokeToken.bind(null, apiToken),
  }];

  actionMenuElement.value.open(event, event.currentTarget);
}

const isValid = computed(() => {
  if (!tokenName.value) return false;
  if (!(tokenScope.value === 'r' || tokenScope.value === 'rw')) return false;
  return true;
});

async function refreshApiTokens() {
  const [error, tokens] = await tokensModel.list();
  if (error) return console.error(error);

  apiTokens.value = tokens.filter(function (c) { return c.clientId === TOKEN_TYPES.ID_SDK; });
}

async function onSubmitAddApiToken(){
  if (!isValid.value) return;

  const scope = { '*': tokenScope.value };
  const allowedIpRanges = tokenAllowedIpRanges.value;
  const [error, apiToken] = await tokensModel.add(tokenName.value, scope, allowedIpRanges);
  if (error) {
    tokenAllowedIpRangesError.value = error.body ? error.body.message : 'Internal error';
    return;
  }

  addedToken.value = apiToken.accessToken;

  await refreshApiTokens();
}

function onCopyToClipboard(apiToken) {
  copyToClipboard(apiToken);
  window.pankow.notify({ type: 'success', text: 'API Token copied!' });
}

function onReset() {
  setTimeout(() => {
    addedToken.value = '';
    tokenName.value = '';
    tokenScope.value = 'rw';
    tokenAllowedIpRanges.value = '';
    tokenAllowedIpRangesError.value = '';
  }, 500);
}

async function onRevokeToken(apiToken) {
  const yes = await inputDialog.value.confirm({
    message: t('profile.removeApiToken.title', { name: apiToken.name }),
    confirmStyle: 'danger',
    confirmLabel: t('main.dialog.yes'),
    rejectLabel: t('main.dialog.no')
  });

  if (!yes) return;

  const [error] = await tokensModel.remove(apiToken.id);
  if (error) return console.error(error);

  await refreshApiTokens();
}

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

</script>

<template>
  <div>
    <Menu ref="actionMenuElement" :model="actionMenuModel" />
    <InputDialog ref="inputDialog" />

    <Dialog ref="newDialog"
      :title="$t('profile.createApiToken.title')"
      :confirm-label="addedToken ? '' : $t('profile.createApiToken.generateToken')"
       confirm-style="primary"
      :reject-label="$t('main.dialog.close')"
       reject-style="secondary"
      @confirm="onSubmitAddApiToken()"
      @close="onReset()"
    >
      <div>
        <Transition name="slide-left" mode="out-in">
          <div v-if="!addedToken">
            <form @submit.prevent="onSubmitAddApiToken()" autocomplete="off">
              <input style="display: none" type="submit" :disabled="!isValid"/>
              <FormGroup>
                <label for="apiTokenName">{{ $t('profile.createApiToken.name') }}</label>
                <TextInput id="apiTokenName" v-model="tokenName" required/>
              </FormGroup>

              <FormGroup>
                <label>{{ $t('profile.createApiToken.access') }}</label>
                <Radiobutton v-model="tokenScope" value="r" :label="$t('profile.apiTokens.readonly')" />
                <Radiobutton v-model="tokenScope" value="rw" :label="$t('profile.apiTokens.readwrite')" />
              </FormGroup>

              <FormGroup>
                <label for="">{{ $t('profile.createApiToken.allowedIpRanges') }}</label>
                <div class="has-error" v-show="tokenAllowedIpRangesError">{{ tokenAllowedIpRangesError }}</div>
                <TextInput v-model="tokenAllowedIpRanges" :placeholder="$t('profile.apiTokens.allowedIpRangesPlaceholder')" />
              </FormGroup>
            </form>
          </div>
          <div v-else>
            <p>{{ $t('profile.createApiToken.description') }}</p>
            <InputGroup>
              <TextInput v-model="addedToken" readonly style="flex-grow: 1;"/>
              <Button tool @click="onCopyToClipboard(addedToken)" icon="fa fa-clipboard" />
            </InputGroup>
            <p>{{ $t('profile.createApiToken.copyNow') }}</p>
          </div>
        </Transition>
      </div>
    </Dialog>

    <Section :title="$t('profile.apiTokens.title')">
      <template #header-buttons>
        <Button @click="newDialog.open()">{{ $t('main.action.add') }}</Button>
      </template>

      <div v-html="$t('profile.apiTokens.description', { apiDocsLink: 'https://docs.cloudron.io/api.html' })"></div>
      <br/>

      <TableView :columns="columns" :model="apiTokens" :placeholder="$t('profile.apiTokens.noTokensPlaceholder')">
        <template #lastUsedTime="apiToken">
          <span v-if="apiToken.lastUsedTime">{{ prettyLongDate(apiToken.lastUsedTime) }}</span>
          <span v-else>{{ $t('profile.apiTokens.neverUsed') }}</span>
        </template>
        <template #scope="apiToken">
          <span v-if="apiToken.scope['*'] === 'rw'">{{ $t('profile.apiTokens.readwrite') }}</span>
          <span v-else>{{ $t('profile.apiTokens.readonly') }}</span>
        </template>
        <template #allowedIpRanges="apiToken">
          <span v-if="apiToken.allowedIpRanges !== ''" v-tooltip="apiToken.allowedIpRanges">{{ apiToken.allowedIpRanges }}</span>
          <span v-else>{{ '*' }}</span>
        </template>
        <template #actions="apiToken">
          <div style="text-align: right;">
            <Button tool plain secondary @click.capture="onActionMenu(apiToken, $event)" icon="fa-solid fa-ellipsis" />
          </div>
        </template>
      </TableView>
    </Section>
  </div>
</template>
