<script setup>

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

import moment from 'moment-timezone';
import { ref, onMounted, useTemplateRef } from 'vue';
import { Button, ClipboardButton, Dialog, InputDialog, FormGroup, Radiobutton, TableView, TextInput, InputGroup } from '@cloudron/pankow';
import { prettyLongDate } from '@cloudron/pankow/utils';
import { TOKEN_TYPES } from '../constants.js';
import ActionBar from './ActionBar.vue';
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
  },
  scope: {
    label: t('profile.apiTokens.scope'),
    hideMobile: true,
  },
  allowedIpRanges: {
    label: t('profile.apiTokens.allowedIpRanges'),
    hideMobile: true,
    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;
    }
  },
  actions: {
    width: '55px',
  },
};

function createActionMenu(apiToken) {
  return [{
    icon: 'fa-solid fa-trash-alt',
    label: t('main.action.remove'),
    action: onRevokeToken.bind(null, apiToken),
  }];
}

const form = useTemplateRef('form');
const isFormValid = ref(false);
function checkValidity() {
  isFormValid.value = form.value ? form.value.checkValidity() : false;

  if (isFormValid.value) {
    if (!(tokenScope.value === 'r' || tokenScope.value === 'rw')) isFormValid.value = false;
  }
}

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 (!form.value.reportValidity()) 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 onReset() {
  setTimeout(() => {
    addedToken.value = '';
    tokenName.value = '';
    tokenScope.value = 'rw';
    tokenAllowedIpRanges.value = '';
    tokenAllowedIpRangesError.value = '';
    setTimeout(checkValidity, 100); // update state of the confirm button
  }, 500);
}

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

  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>
    <InputDialog ref="inputDialog" />

    <Dialog ref="newDialog"
      :title="$t('profile.createApiToken.title')"
      :confirm-label="addedToken ? '' : $t('main.action.add')"
      :confirm-active="isFormValid"
       confirm-style="primary"
      :reject-label="addedToken ? $t('main.dialog.close') : $t('main.dialog.cancel')"
       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" ref="form" @input="checkValidity()">
              <input style="display: none" type="submit"/>
              <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" />
                <small class="helper-text">{{ $t('profile.apiTokens.allowedIpRangesPlaceholder') }}</small>
              </FormGroup>
            </form>
          </div>
          <div v-else>
            <p>{{ $t('profile.createApiToken.description') }}</p>
            <InputGroup>
              <TextInput v-model="addedToken" readonly style="flex-grow: 1;"/>
              <ClipboardButton :value="addedToken" />
            </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="{ item:apiToken }">
          <span v-if="apiToken.lastUsedTime">{{ prettyLongDate(apiToken.lastUsedTime) }}</span>
          <span v-else>{{ $t('profile.apiTokens.neverUsed') }}</span>
        </template>
        <template #scope="{ item:apiToken }">
          <span v-if="apiToken.scope['*'] === 'rw'">{{ $t('profile.apiTokens.readwrite') }}</span>
          <span v-else>{{ $t('profile.apiTokens.readonly') }}</span>
        </template>
        <template #allowedIpRanges="{ item:apiToken }">
          <span v-if="apiToken.allowedIpRanges !== ''">{{ apiToken.allowedIpRanges }}</span>
          <span v-else>{{ '*' }}</span>
        </template>
        <template #actions="{ item:apiToken }">
          <ActionBar :actions="createActionMenu(apiToken)" />
        </template>
      </TableView>
    </Section>
  </div>
</template>
