<script setup>

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

import { ref, onMounted, onBeforeUnmount, computed, useTemplateRef } from 'vue';
import { Button, ButtonGroup, SingleSelect, InputDialog } from '@cloudron/pankow';
import PostInstallDialog from '../components/PostInstallDialog.vue';
import SftpInfoDialog from '../components/SftpInfoDialog.vue';
import Access from '../components/app/Access.vue';
import Backups from '../components/app/Backups.vue';
import Cron from '../components/app/Cron.vue';
import Display from '../components/app/Display.vue';
import Email from '../components/app/Email.vue';
import Eventlog from '../components/app/Eventlog.vue';
import Graphs from '../components/app/Graphs.vue';
import Info from '../components/app/Info.vue';
import Location from '../components/app/Location.vue';
import Proxy from '../components/app/Proxy.vue';
import Resources from '../components/app/Resources.vue';
import Repair from '../components/app/Repair.vue';
import Security from '../components/app/Security.vue';
import Services from '../components/app/Services.vue';
import Storage from '../components/app/Storage.vue';
import Uninstall from '../components/app/Uninstall.vue';
import Updates from '../components/app/Updates.vue';
import AppsModel from '../models/AppsModel.js';
import TasksModel from '../models/TasksModel.js';
import { API_ORIGIN, APP_TYPES, ISTATES, RSTATES, HSTATES } from '../constants.js';

const appsModel = AppsModel.create();
const tasksModel = TasksModel.create();
const installationStateLabel = AppsModel.installationStateLabel;

const busy = ref(true);
const id = ref('');
const app = ref(null);
const currentView = ref('');
const link = ref('');
const infoMenu = ref([]);
const hasLocalStorage = ref(false);
const hasOptionalServices = ref(false);
const hasEmail = ref(false);
const busyStopTask = ref(false);
const postInstallDialog = useTemplateRef('postInstallDialog');
const sftpInfoDialog = useTemplateRef('sftpInfoDialog');
const inputDialog = useTemplateRef('inputDialog');

const isAppStopped = computed(() => {
  return appsModel.isStopped(app.value);
});

function onSetView(newView) {
  currentView.value = newView;
  window.location.hash = `/app/${id.value}/${newView}`;
}

const toggleRunStateBusy = ref(false);
async function onToggleRunState() {
  if (isAppStopped.value) {
    toggleRunStateBusy.value = true;
    const [error] = await appsModel.start(app.value.id);
    if (error) return console.error(error);
  } else {
    const confirmed = await inputDialog.value.confirm({
      message: t('app.stopDialog.title', { app: app.value.label || app.value.fqdn }),
      confirmStyle: 'danger',
      confirmLabel: t('main.dialog.yes'),
      rejectLabel: t('main.dialog.no'),
      rejectStyle: 'secondary',
    });

    if (!confirmed) return;

    toggleRunStateBusy.value = true;
    const [error] = await appsModel.stop(app.value.id);
    if (error) return console.error(error);
  }
  setTimeout(() => toggleRunStateBusy.value = false, 2000);
}

let refreshTimer = null;
async function refresh() {
  const [error, result] = await appsModel.get(id.value);
  if (error) {
    if (error.status === 403) return window.location.hash = '/';
    else if (error.status === 404) return window.location.hash = '/apps';
    return console.error(error);
  }

  // prevent users who have no acces to
  if (result.accessLevel !== 'admin' && result.accessLevel !== 'operator') return window.location.hash = '/';

  app.value = result;

  link.value = (result.installationState !== ISTATES.INSTALLED || result.health !== HSTATES.HEALTHY || result.runState === RSTATES.STOPPED) ? '' : `https://${result.fqdn}`;
  hasLocalStorage.value = result.manifest && result.manifest.addons && result.manifest.addons.localstorage;
  hasOptionalServices.value = result.manifest && result.manifest.addons && (result.manifest.addons.turn?.optional || result.manifest.addons.redis?.optional);
  hasEmail.value = result.manifest && result.manifest.addons && (result.manifest.addons.sendmail || result.manifest.addons.recvmail);

  infoMenu.value = [];
  infoMenu.value.push({
    label: t('app.docsAction'),
    disabled: !result.manifest?.documentationUrl,
    href: result.manifest.documentationUrl,
    target: '_blank',
  });

  if (result.manifest?.postInstallMessage) {
    infoMenu.value.push({
      label: t('app.firstTimeSetupAction'),
      action: () => postInstallDialog.value.open(app.value),
    });
  }

  if (result.manifest?.configurePath) {
    infoMenu.value.push({
      label: t('app.adminPageAction'),
      href: link.value + result.manifest.configurePath,
      target: '_blank',
    });
  }

  if (result.manifest?.addons?.localstorage?.ftp) {
    infoMenu.value.push({
      label: t('app.sftpInfoAction'),
      action: () => sftpInfoDialog.value.open(app.value),
    });
  }

  infoMenu.value.push({ separator: true });
  infoMenu.value.push({
    label: t('app.forumUrlAction'),
    disabled: !result.manifest?.forumUrl,
    href: result.manifest.forumUrl,
    target: '_blank',

  });
  infoMenu.value.push({ separator: true });
  infoMenu.value.push({
    label: t('app.projectWebsiteAction'),
    disabled: !result.manifest?.website,
    href: result.manifest.website,
    target: '_blank',
  });

  refreshTimer = setTimeout(refresh, 2000);
}

async function onStopAppTask() {
  if (!app.value.taskId) return;

  busyStopTask.value = true;

  const [error] = await tasksModel.stop(app.value.taskId);
  if (error) console.error(error);

  busyStopTask.value = false;
}

const views = ref([]);

onMounted(async () => {
  const tmp = window.location.hash.slice('#/app/'.length);
  if (!tmp) return;

  const parts = tmp.split('/');
  if (parts.length !== 2) return;

  id.value = parts[0];

  await refresh();
  if (!app.value) return;

  let hasServices = false;
  if (app.value.manifest.addons.turn && app.value.manifest.addons.turn.optional) hasServices = true;
  if (app.value.manifest.addons.redis && app.value.manifest.addons.redis.optional) hasServices = true;

  views.value.push({ id: 'info', display: t('app.infoTabTitle'), });
  views.value.push({ id: 'display', display: t('app.displayTabTitle'), });
  if (app.value.accessLevel === 'admin') views.value.push({ id: 'location', display: t('app.locationTabTitle'), });
  if (app.value.type === APP_TYPES.PROXIED) views.value.push({ id: 'proxy', display: 'Proxy', });
  if (app.value.accessLevel === 'admin') views.value.push({ id: 'access', display: t('app.accessControlTabTitle'), });
  if (app.value.type !== APP_TYPES.PROXIED) views.value.push({ id: 'resources', display: t('app.resourcesTabTitle'), });
  if (app.value.type !== APP_TYPES.PROXIED && hasServices) views.value.push({ id: 'services', display: t('app.servicesTabTitle'), });
  if (app.value.accessLevel === 'admin' && app.value.type !== APP_TYPES.PROXIED) views.value.push({ id: 'storage', display: t('app.storageTabTitle'), });
  if (app.value.type !== APP_TYPES.PROXIED) views.value.push({ id: 'graphs', display: t('app.graphsTabTitle'), });
  views.value.push({ id: 'security', display: t('app.securityTabTitle'), });
  if (app.value.accessLevel === 'admin' && hasEmail.value && app.value.type !== APP_TYPES.PROXIED) views.value.push({ id: 'email', display: t('app.emailTabTitle'), });
  if (app.value.type !== APP_TYPES.PROXIED) views.value.push({ id: 'cron', display: t('app.cronTabTitle'), });
  views.value.push({ id: 'updates', display: t('app.updatesTabTitle'), });
  if (app.value.type !== APP_TYPES.PROXIED) views.value.push({ id: 'backups', display: t('app.backupsTabTitle'), });
  views.value.push({ id: 'repair', display: t('app.repairTabTitle'), });
  views.value.push({ id: 'eventlog', display: t('app.eventlogTabTitle'), });
  if (app.value.accessLevel === 'admin') views.value.push({ id: 'uninstall', display: t('app.uninstallTabTitle'), });

  onSetView(parts[1] || 'info');

  busy.value = false;
});

onBeforeUnmount(() => {
  if (refreshTimer) clearTimeout(refreshTimer);
});

</script>

<template>
  <div class="configure-outer">
    <PostInstallDialog ref="postInstallDialog"/>
    <SftpInfoDialog ref="sftpInfoDialog"/>
    <InputDialog ref="inputDialog"/>

    <div class="configure-inner" v-if="!busy">
      <div class="titlebar">
        <div style="display: flex; flex-grow: 1; overflow: hidden;">
          <img :src="app.iconUrl" v-fallback-image="API_ORIGIN + '/img/appicon_fallback.png'" style="height: 64px; width: 64px; margin-right: 10px;"/>
          <h2>
            <a class="applink" :href="link || null" target="_blank">{{ app.label || app.fqdn }}</a>
            <div class="statelabel">
              {{ installationStateLabel(app) }} {{ app.message ? ' - ' + app.message : '' }}
            </div>
          </h2>
        </div>

        <div class="titlebar-toolbar">
          <SingleSelect class="pankow-no-desktop" v-model="currentView" :options="views" optionKey="id" optionLabel="display" @select="onSetView"/>
          <div style="display: flex; gap: 10px">
            <Button v-if="app.taskId" danger tool plain icon="fa-solid fa-xmark" v-tooltip="'Cancel Task'" :loading="busyStopTask" :disabled="busyStopTask" @click="onStopAppTask()"/>
            <Button secondary tool
              @click="onToggleRunState()"
              :disabled="toggleRunStateBusy || app.taskId || app.error || app.installationState === 'pending_start' || app.installationState === 'pending_stop'"
              v-tooltip="$t(isAppStopped ? 'app.uninstall.startStop.startAction' : 'app.uninstall.startStop.stopAction')"
              :loading="toggleRunStateBusy || app.installationState === 'pending_start' || app.installationState === 'pending_stop'"
              :icon="isAppStopped ? 'fa-solid fa-play' : 'fa-solid fa-power-off'"
            />
            <ButtonGroup>
              <Button secondary tool :href="`/logs.html?appId=${app.id}`" target="_blank" v-tooltip="$t('app.logsActionTooltip')" icon="fa-solid fa-align-left" />
              <Button secondary tool v-if="app.type !== APP_TYPES.PROXIED" :href="`/terminal.html?id=${app.id}`" target="_blank" v-tooltip="$t('app.terminalActionTooltip')" icon="fa fa-terminal" />
              <Button secondary tool v-if="hasLocalStorage" :href="`/filemanager.html#/home/app/${app.id}`" target="_blank" v-tooltip="$t('app.filemanagerActionTooltip')" icon="fas fa-folder" />
            </ButtonGroup>

            <Button secondary tool icon="fa-solid fa-book" v-tooltip="$t('app.docsActionTooltip')" :menu="infoMenu" />
          </div>
        </div>
      </div>

      <div class="apptask-progress">
        <div class="apptask-progress-filled" :style="{ width: app.progress+'%' }"></div>
      </div>

      <div class="configure-body">
        <div class="configure-menu pankow-no-mobile">
          <div class="configure-menu-item" v-for="view in views" :key="view.id" @click="onSetView(view.id)" :active="currentView === view.id ? true : null">{{ view.display }}</div>
        </div>
        <div class="configure-content">
          <Transition name="slide-fade" mode="out-in">
            <Info v-if="currentView === 'info'" :app="app"/>
            <Display v-else-if="currentView === 'display'" :app="app"/>
            <Location v-else-if="currentView === 'location'" :app="app"/>
            <Proxy v-else-if="currentView === 'proxy'" :app="app"/>
            <Access v-else-if="currentView === 'access'" :app="app"/>
            <Resources v-else-if="currentView === 'resources'" :app="app"/>
            <Services v-else-if="currentView === 'services'" :app="app"/>
            <Storage v-else-if="currentView === 'storage'" :app="app"/>
            <Graphs v-else-if="currentView === 'graphs'" :app="app"/>
            <Security v-else-if="currentView === 'security'" :app="app"/>
            <Email v-else-if="currentView === 'email'" :app="app"/>
            <Cron v-else-if="currentView === 'cron'" :app="app"/>
            <Updates v-else-if="currentView === 'updates'" :app="app"/>
            <Backups v-else-if="currentView === 'backups'" :app="app"/>
            <Repair v-else-if="currentView === 'repair'" :app="app"/>
            <Eventlog v-else-if="currentView === 'eventlog'" :app="app"/>
            <Uninstall v-else-if="currentView === 'uninstall'" :app="app"/>
          </Transition>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>

.applink {
  display: flex;
  align-items: center;
  color: var(--pankow-text-color);
}

.titlebar {
  display: flex;
  gap: 10px;
  justify-content: space-between;
}

.titlebar h2 {
  overflow: hidden;
  flex-grow: 1;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.titlebar-toolbar {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
}

@media (max-width: 576px) {
  .titlebar-toolbar {
    flex-grow: 1;
  }
}

.statelabel {
  font-size: 12px;
  margin-top: 6px;
  text-overflow: ellipsis;
  overflow: hidden;
  text-wrap: nowrap;
}

.applink:not([href]) {
  cursor: not-allowed;
}

.configure-outer {
  width: 100%;
  margin: auto;
  margin-top: 0;
}

.configure-inner {
  width: 100%;
  max-width: 1200px;
  margin: auto;
  padding: 0 15px;
}

.apptask-progress {
  position: relative;
  width: 100%;
  height: 5px;
  text-align: center;
  border-radius: 10px;
  color: var(--pankow-text-color);
  margin-top: 4px;
}

.apptask-progress-filled {
  background-color: var(--pankow-color-primary);
  position: relative;
  top: 0;
  left: 0;
  height: 100%;
  border-radius: 10px;
  z-index: 1;
  background-image: linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);
  background-size: 40px 40px;
  animation: apptask-progress-bar-stripes 1s linear infinite;
  transition: width 300ms;
}

@keyframes apptask-progress-bar-stripes {
  from {
    background-position: 40px 0;
  }
  to {
    background-position: 0 0;
  }
}

.configure-body {
  margin-top: 20px;
  margin-bottom: 10px;
  display: flex;
}

.configure-menu-item {
  white-space: nowrap;
  cursor: pointer;
  padding: 4px 60px 4px 4px;
}

.configure-menu-item[active] {
  color: var(--pankow-color-primary-active);
  font-weight: bold;
}

.configure-menu-item:hover {
  color: var(--pankow-color-primary-hover);
}

.configure-content {
  flex-grow: 1;
}

</style>
