<template>
  <div class="pt-4 sticky-top text-center">
    <button
      class="btn btn-success btn-lg btn-block"
      @click="publish"
      :disabled="!mayUpdate || changed || hasRecurringSchedules"
      v-if="!versionIsLive"
    >
      <span class="icon-rocket"></span>
      Live zetten
    </button>
    <button class="btn btn-warning btn-block" @click="depublish" v-if="versionIsLive && mayDepublish" :disabled="hasRecurringSchedules">
      <span class="icon-switch"></span>
      Depubliceren
    </button>

    <hr />

    <p>Wijzigingen</p>
    <div class="btn-block">
      <submit button-class="btn btn-primary btn-block" :action="save" :disabled="!mayUpdate || isSavingVersion">
        <span v-if="isSavingVersion" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
        <span v-else class="icon-floppy-disk"></span>
        <span v-if="versionIsLive"> Opslaan & live zetten </span>
        <span v-else> Opslaan </span>
      </submit>
    </div>
    <button class="btn btn-primary btn-block" @click="cancel" :disabled="!changed">
      <span class="icon-undo"></span>
      Ongedaan maken
    </button>

    <hr />

    <p>Versie</p>
    <button v-if="page.versions.length != 1" class="btn btn-danger btn-block" @click="handleDeleteVersion" :disabled="!mayDelete">
      <span class="icon-cross"></span>
      <span v-if="version && page.versions.length != 1">Verwijderen</span>
    </button>
    <button class="btn btn-info btn-block" @click="handleCopyVersion" :disabled="!mayCreate">
      <span class="icon-copy"></span>
      <span>Kopiëren</span>
    </button>
    <button class="btn btn-info btn-block" @click="openPreview" :disabled="!previewUrl">
      <i class="icon-eye"></i>
      Preview
    </button>
  </div>
</template>

<style>
.separator {
  display: flex;
  align-items: center;
  text-align: center;
}
.separator::before,
.separator::after {
  content: '';
  flex: 1;
  border-bottom: 1px solid #000;
}
.separator::before {
  margin-right: 0.25em;
}
.separator::after {
  margin-left: 0.25em;
}
</style>

<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { namespace } from 'vuex-class';
import { SchemaItem, Version, VersionedPage } from '../types/api';
import formElements from '../shared/form/all';
import PageApi from '../api/page-api';
import ConfirmDialog from '../shared/form/confirm-dialog.vue';

const PermissionsStore = namespace('permissions');
const AlertsStore = namespace('alerts');
const PagesStore = namespace('pages');

@Component({
  components: {
    ...formElements
  }
})
export default class VersionActions extends Vue {
  previewWindow: any | null = null; // TODO fix propper DOM Window type

  @PermissionsStore.Getter('canCreate') readonly canCreate!: Function;
  @PermissionsStore.Getter('canUpdate') readonly canUpdate!: Function;
  @PermissionsStore.Getter('canDelete') readonly canDelete!: Function;
  @AlertsStore.Action('addSuccess') readonly addSuccess!: Function;
  @AlertsStore.Action('addCmsError') readonly addCmsError!: Function;
  @PagesStore.Action('updateVersion') readonly updateVersion!: Function;
  @PagesStore.Action('publishVersion') readonly publishVersion!: Function;
  @PagesStore.Action('depublishVersion') readonly depublishVersion!: Function;
  @PagesStore.Action('deleteVersion') readonly deleteVersion!: Function;

  @Prop() readonly schema!: SchemaItem;
  @Prop() readonly allPublished!: Version[];
  @Prop() readonly version!: Version;
  @Prop() readonly changed!: boolean;
  @Prop() readonly hasRecurringSchedules!: boolean;
  @Prop() readonly resetChanged!: Function;
  @Prop() readonly versionIsLive!: boolean;
  @Prop() readonly dialog!: ConfirmDialog | undefined;
  @Prop() readonly page!: VersionedPage | null;
  @Prop() readonly versionIsPublished!: boolean;
  @Prop() readonly previewUrl!: string | null;

  isSavingVersion = false;

  async save() {
    this.isSavingVersion = true;
    try {
      await this.updateVersion(this.version);
      this.resetChanged();
      await this.addSuccess('Pagina is opgeslagen!');
    } catch (e) {
      await this.addCmsError(e);
    } finally {
      this.isSavingVersion = false;
    }
  }

  async publish() {
    try {
      const pageVersion = await this.publishVersion(this.version);
      this.handlePublication(pageVersion);
      await this.addSuccess('Deze versie staat nu live!');
    } catch (e) {
      await this.addCmsError(e);
    }
  }

  async depublish() {
    try {
      if (this.version && this.version.id) {
        const referenceInfo = await PageApi.getReferenceInfoForVersion(this.version.id);
        const message = referenceInfo.isSafeToDepublishOrDelete
          ? 'Weet je zeker dat je deze versie wilt depubliceren?'
          : `Pas op: deze pagina wordt nog gebruikt op: ${referenceInfo.pageReferences
              .map((r) => `'${r.path}'`)
              .join(', ')}, weet je zeker dat je deze versie wilt depubliceren?`;
        await this.dialog.confirm('Depubliceren', message, 'Ja, depubliceren');
      }
      try {
        const pageVersion = await this.depublishVersion(this.version);
        this.handlePublication(pageVersion);
      } catch (e) {
        await this.addCmsError(e);
      }
    } catch (error) {
      // Do nothing if confirm is cancelled
    }
  }

  async handleCopyVersion() {
    if (!this.version || !this.page) {
      return;
    }
    const pageId = this.page.id;

    const version = await PageApi.copyVersion(this.version.id);
    this.$nextTick(() => {
      this.$router.push({
        name: 'page-editor-version',
        params: { id: pageId, versionId: version.id }
      });
    });
  }

  async cancel() {
    try {
      await this.dialog.confirm('Herstellen', 'Weet je zeker dat je de wijzigingen ongedaan wilt maken?');
      this.$emit('cancelChanges');
    } catch (error) {
      // Do nothing if confirm is cancelled
    }
  }

  async handleDeleteVersion() {
    if (!this.page || !this.version) {
      return;
    }
    try {
      const referenceInfo = this.version ? await PageApi.getReferenceInfoForVersion(this.version.id) : null;
      const message =
        !referenceInfo || referenceInfo.isSafeToDepublishOrDelete
          ? 'Weet je zeker dat je deze versie wilt verwijderen?'
          : `Pas op: deze pagina wordt nog beruikt op: ${referenceInfo.pageReferences
              .map((r) => `'${r.path}'`)
              .join(', ')}, weet je zeker dat je deze versie wilt verwijderen?`;
      await this.dialog.confirm('Verwijderen', message);
      try {
        await this.deleteVersion(this.version);
        this.resetChanged();
        this.$router.push({
          name: 'page-editor',
          params: { id: this.page.id }
        });
        await this.addSuccess('De versie is verwijderd');
      } catch (error) {
        await this.addCmsError(error);
        throw error;
      }
    } catch (error) {
      // Do nothing if confirm is cancelled
    }
  }

  handlePublication(version: Version) {
    if (!this.version) {
      return;
    }
    this.version.publishDate = version.publishDate;
    this.version.depublishDate = version.depublishDate;
    this.resetChanged();
  }

  openPreview() {
    if (!this.previewUrl) return;
    this.previewWindow = window.open(this.previewUrl);
  }

  get mayUpdate() {
    // TODO: use meta.itemName when child classes are returned in the permissions api
    return this.canUpdate('CmsPage');
  }
  get mayDepublish() {
    // TODO: use meta.itemName when child classes are returned in the permissions api
    return this.canUpdate('CmsPage') && (!this.schema.preventDepublish || this.allPublished.length > 1);
  }

  get mayCreate() {
    // TODO: use meta.itemName when child classes are returned in the permissions api
    return this.canCreate('CmsPage');
  }

  get mayDelete() {
    // TODO: use meta.itemName when child classes are returned in the permissions api
    return (
      this.canDelete('CmsPage') &&
      (!this.version || ((!this.schema.preventDelete || (this.page && this.page.versions.length > 1)) && !this.versionIsPublished))
    );
  }

  @Watch('previewUrl', { immediate: true })
  onPreviewUrlChange() {
    // update preview window with the new version
    try {
      this.previewWindow!.location = this.previewUrl;
    } catch (e) {
      // errors can safely be ignored
    }
  }
}
</script>
