<template>
  <loader ref="loader">
    <div class="page-editor pt-3">
      <validator-group>
        <div v-if="page" class="row">
          <div class="col-8">
            <h1>
              {{ version ? version.metaTitle : page.name }}
              <span v-if="isReadOnly" class="crud-editor-readonly-title">[ Alleen lezen ]</span>
            </h1>
            <p>
              <a v-if="!isFolder && publicUrl && state.published" :href="publicUrl" target="_blank">
                {{ publicUrl }}
              </a>
              <span class="text-secondary" v-else-if="!isFolder && publicUrl">
                {{ publicUrl }}
              </span>
            </p>
          </div>
          <div class="col-4 text-right">
            <div>
              <small>
                Aangemaakt op: {{ createdDate }}
                <span v-if="createdBy">door {{ createdBy }} </span>
              </small>
            </div>
            <div>
              <small>
                Aangepast op: {{ modifiedDate }}
                <span v-if="modifiedBy">door {{ modifiedBy }} </span>
              </small>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-12">
            <div class="container-fluid">
              <div class="row align-items-center">
                <strong class="mr-1">{{ isFolder ? 'Folder' : schema?.title || 'Pagina' }}</strong>
                <p class="mx-1 mb-0">•</p>
                <div v-if="!isReadOnly" class="page-buttons">
                  <button class="btn btn-light btn-sm mx-1" @click="openModal">Instellingen</button>
                  <modal ref="modal">
                    <div class="modal-header">
                      <h4 class="modal-title">Pagina instellingen</h4>
                    </div>

                    <div class="modal-body container">
                      <page-editor-header :translations="translations" :page="page" :isFolder="isFolder"></page-editor-header>
                    </div>
                    <div class="modal-footer">
                      <button class="btn btn-secondary" @click="closeModal">Sluit</button>
                    </div>
                  </modal>
                  <dropdown-menu v-if="!isSingleton && page" label="Acties" buttonClass="btn-light btn-sm mx-1 h-100">
                    <router-link v-if="!isFolder" :to="{ name: 'copy-page', params: { pageId: page.id } }" class="dropdown-item">
                      Pagina kopieren
                    </router-link>
                    <button
                      v-if="isFolder || (page.versions.length == 1 && !isSingleton)"
                      @click="handleDelete"
                      :disabled="!mayDelete"
                      class="dropdown-item"
                    >
                      {{ isFolder ? 'Folder' : 'Pagina' }} verwijderen
                    </button>
                  </dropdown-menu>
                  <dropdown-menu
                    v-if="!isFolder"
                    :label="languageDisplayName"
                    buttonClass="btn-light btn-sm mx-1 h-100"
                    dropdownName="translateItem"
                  >
                    <ul class="list-unstyled m-0">
                      <li v-for="translated in translateds" :key="translated.languageInfo.language">
                        <router-link
                          :to="{
                            name: 'page-editor',
                            params: { id: translated.id }
                          }"
                          class="dropdown-item"
                          >{{ translated.languageInfo.displayName }}
                        </router-link>
                      </li>
                    </ul>
                    <div v-if="page && translatables.length > 0">
                      <div class="dropdown-divider"></div>
                      <ul class="list-unstyled m-0">
                        <li>
                          <router-link
                            :to="{
                              name: 'translate-page',
                              params: { pageId: page.id }
                            }"
                            class="dropdown-item"
                            >Vertaal pagina
                          </router-link>
                        </li>
                      </ul>
                    </div>
                  </dropdown-menu>
                </div>
                <redirects v-if="version && !isReadOnly" ref="redirects" :page="page">
                  <template slot="button" slot-scope="{ redirects, openModal }">
                    <button @click.prevent="openModal" class="btn btn-light btn-sm mx-1 h-100">
                      <span class="icon-new-tab"></span>
                      Redirects ({{ redirects.length }})
                    </button>
                  </template>
                </redirects>
                <references
                  ref="refsDialog"
                  v-if="!isNew && version"
                  :item-id="version.pageId"
                  :item-name="version.page.name"
                  buttonClass="btn btn-sm mx-1 btn-light"
                ></references>
              </div>
            </div>
          </div>
        </div>
        <div v-if="isFolder">
          <hr />
          <div class="alert alert-info">Dit is een folder.</div>
        </div>
        <div v-else-if="!hasPublishedVersions">
          <hr />
          <div class="alert alert-warning">
            Deze pagina heeft geen gepubliceerde versie(s)
            <redirects v-if="page" ref="redirects" :page="page">
              <template slot="button" slot-scope="{ redirects, openModal, alertRedirectNeeded }">
                <span v-if="redirects.length">en heeft een <a href="#" @click.prevent="openModal">redirect</a>.</span>
                <span v-else>en geeft een 404.&nbsp;&nbsp;</span>
                <button class="btn btn-primary" v-if="!redirects.length" :class="{ alertRedirectNeeded }" @click.prevent="openModal">
                  Maak een redirect aan
                </button>
              </template>
            </redirects>
          </div>
        </div>
        <hr />
        <template v-if="version">
          <div class="row">
            <div class="col-12 input-group mb-3">
              <div class="input-group-prepend">
                <label class="input-group-text" for="version">Geselecteerde versie:</label>
              </div>
              <select class="custom-select" id="version" v-model="selectedVersionId">
                <option v-for="(version, index) in page?.versions" :key="index" :value="version.id">
                  {{ version.name || 'Versie 1' }}
                  <span v-if="version == live" class="badge badge-success"> (Live)</span>
                  <span v-else-if="scheduled(version)"> (Scheduled)</span>
                </option>
              </select>
            </div>
          </div>
          <div class="row">
            <div class="column col-12">
              <version-editor
                :version="version"
                :state="state"
                :permissions="permissions"
                :dialog="dialog"
                :isNew="isNew"
                :isReadOnly="isReadOnly"
                :allPublished="allPublished"
                :versionIsPublished="state.published"
                :versionEditor="versionEditor"
                :page="page"
                @cancelChanges="cancelChanges"
                ref="version-editor"
              ></version-editor>
            </div>
          </div>
        </template>
        <confirm-dialog ref="dialog"></confirm-dialog>
      </validator-group>
    </div>
  </loader>
</template>

<style lang="scss" scoped>
.page-editor {
  margin: 0 auto;
  max-width: 1600px;
}

.nav-item {
  &.copy {
    margin: 5px;
  }

  &.text-link-right {
    margin: 5px 0 5px auto;
  }
}

.page-buttons {
  display: flex;
}
</style>

<script lang="ts">
import dayjs from 'dayjs';
import { Component, Prop, Ref, Vue, Watch } from 'vue-property-decorator';
import { Route } from 'vue-router';
import { namespace } from 'vuex-class';
import PageApi from '../api/page-api';
import TranslationsApi from '../api/translations-api';
import formElements from '../shared/form/all';
import ConfirmDialog from '../shared/form/confirm-dialog.vue';
import loader from '../shared/loader.vue';
import modal from '../shared/modal.vue';
import redirects from '../shared/redirects.vue';
import references from '../shared/references.vue';
import { PermissionTypes } from '../stores/types/PermissionStoreModel';
import { Translation } from '../stores/types/TranslationStoreModel';
import { SchemaItem, Version, VersionedPage } from '../types/api';
import pageEditorHeader from './page-editor-header.vue';
import VersionEditor from './version-editor.vue';
import { getPublishedVersions, isDepublished, isPublished, isScheduled } from './version-utils';

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

@Component({
  components: {
    pageEditorHeader,
    VersionEditor,
    loader,
    redirects,
    modal,
    references,
    ...formElements
  },
  beforeRouteUpdate(to: Route, from: Route, next: Function) {
    (this as PageEditor).confirmChangingRoute(next);
  },
  beforeRouteLeave(to: Route, from: Route, next: Function) {
    (this as PageEditor).confirmChangingRoute(next);
  }
})
export default class PageEditor extends Vue {
  selectedVersionId = '';
  isLoading = false;
  translations: Translation[] = [];
  versionsWithRecurrentSchedules: string[] = [];
  page: VersionedPage | null = null;
  isLeafFolder = false;

  @PermissionsStore.Getter('getPermissions') readonly getPermissions!: 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('deletePage') readonly deletePage!: Function;
  @PagesStore.Getter('types') readonly types!: object;
  @Prop(String) readonly versionId!: string;
  @Ref('version-editor') readonly versionEditor!: VersionEditor;
  @Ref('dialog') readonly dialog!: ConfirmDialog;
  @Ref('refsDialog') readonly refsDialog!: typeof references;

  created() {
    this.fetchData();
  }

  get version(): Version | null {
    return this.page?.versions.find((version) => version.id == this.versionId) ?? null;
  }

  get allPublished(): Version[] | [] {
    return this.page?.versions.length ? getPublishedVersions(this.page.versions) : [];
  }

  get hasPublishedVersions(): boolean {
    return this.page?.versions.some(isPublished) ?? false;
  }

  get live(): Version | null {
    return this.allPublished[0] ?? null;
  }

  get state(): PageEditorState {
    return {
      published: this.published(this.version),
      depublished: this.depublished(this.version),
      scheduled: this.scheduled(this.version),
      live: this.live
    };
  }

  get permissions() {
    return {
      ...this.getPermissions('CmsPage'),
      canDepublish: this.mayDepublish
    };
  }

  get schema(): SchemaItem | null {
    if (this.page && this.page.versions.length) {
      return this.types[this.page.versions[0].$type];
    }

    return null;
  }

  get isFolder(): boolean {
    return this.page && !this.page.versions.length;
  }

  get isSingleton(): boolean {
    return this.schema?.isSingleton ?? false;
  }

  get publicUrl() {
    if (!window.serverSideCmsSettings || !this.page) {
      return null;
    }
    return window.serverSideCmsSettings.baseUrl + this.page.url;
  }

  get translatables() {
    return this.translations.filter((t) => !t.id);
  }

  get translateds() {
    return this.translations.filter((t) => t.id && t.id !== (this.page && this.page.id));
  }

  get languageDisplayName() {
    const translation = this.translations.find((t) => t.id == (this.page && this.page.id));
    return translation ? translation.languageInfo.displayName : '';
  }

  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 mayDelete() {
    if (this.isFolder) {
      return this.isLeafFolder;
    }

    // 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.state.published))
    );
  }

  get isNew() {
    return !(this.page && this.page.id);
  }

  get isReadOnly() {
    return !this.$store.getters['permissions/permissionAllows'](PermissionTypes.Update, this.version);
  }

  get createdDate() {
    return this.page && dayjs(this.page.created).format('LLL');
  }

  get createdBy() {
    return this.page && this.page.createdBy;
  }

  get modifiedDate() {
    return this.page && dayjs(this.page.modified).format('LLL');
  }

  get modifiedBy() {
    return this.page && this.page.modifiedBy;
  }

  openModal() {
    (this.$refs.modal as modal).show();
  }

  closeModal() {
    (this.$refs.modal as modal).hide();
  }

  @Watch('selectedVersionId')
  handleVersionChange() {
    if (this.page && this.version && this.selectedVersionId != this.version.id) {
      this.$router.replace({
        name: 'page-editor-version',
        params: {
          id: this.page.id,
          versionId: this.selectedVersionId
        }
      });
    }
  }

  @Watch('$route')
  async fetchData() {
    this.isLoading = true;
    const page = await PageApi.getPageById(this.$route.params.id);
    this.page = page;
    this.isLeafFolder = await PageApi.isLeafFolder(this.$route.params.id);
    // nextTick, because 'this.live' can only be computed after 'this.page' is set
    this.$nextTick(async () => {
      const version = this.live || page.versions[0];
      if (version) {
        this.$router.replace({
          name: 'page-editor-version',
          params: {
            id: page.id,
            versionId: this.$route.params.versionId || version.id
          }
        });
        this.selectedVersionId = this.$route.params.versionId || version.id;
      }
      this.isLoading = false;
      this.versionsWithRecurrentSchedules = await PageApi.scheduledVersionIds(this.$route.params.id);
      this.fetchTranslations();
    });
  }

  @Watch('page.language')
  async fetchTranslations() {
    return TranslationsApi.getPageTranslations(this.$route.params.id).then((translations) => {
      this.translations = translations;
    });
  }

  hasRecurrentSchedule(version: Version) {
    return this.versionsWithRecurrentSchedules.includes(version.id);
  }

  scheduled(version: Version | null) {
    return isScheduled(version);
  }

  published(version: Version | null) {
    return isPublished(version);
  }

  depublished(version: Version | null) {
    return isDepublished(version);
  }

  async handleDelete() {
    try {
      const pageType = this.isFolder ? 'folder' : 'pagina';
      const referenceInfo = this.version ? await PageApi.getReferenceInfoForVersion(this.version.id) : null;
      const message =
        !referenceInfo || referenceInfo.isSafeToDepublishOrDelete
          ? `Weet je zeker dat je de ${pageType} wilt verwijderen?`
          : `Pas op: deze ${pageType} wordt nog gebruikt op: ${referenceInfo.pageReferences
              .map((r) => `'${r.path}'`)
              .join(', ')}, weet je zeker dat je deze ${pageType} wilt verwijderen?`;
      await this.dialog.confirm('Verwijderen', message);
      try {
        await this.deletePage(this.page);
        if (this.versionEditor) {
          this.versionEditor.changed = false;
        }
        this.$router.push('/pages');
        await this.addSuccess(`De ${pageType} is verwijderd`);
      } catch (error) {
        if (error.isReferenceError) {
          this.refsDialog.openErrorModal();
        }
        await this.addCmsError(error);
      }
    } catch (error) {
      // Do nothing if confirm is cancelled
    }
  }

  async cancelChanges() {
    if (!this.page) {
      return;
    }
    this.page = await PageApi.getPageById(this.page.id);
    this.versionEditor.resetChanged();
  }

  confirmChangingRoute(next: Function) {
    // check if version is changed by user
    if (this.versionEditor && this.versionEditor.changed) {
      this.dialog
        .confirm('Er zijn nog onopgeslagen wijzigingen', 'Weet je zeker dat je ze niet wilt opslaan?', 'Ja, doorgaan', 'Terug')
        .then(() => {
          next();
        })
        .catch(() => {
          // in case you changed versions, we reset the selected version to the current one
          if (this.version) {
            this.selectedVersionId = this.version.id;
          }
        });
    } else {
      next();
    }
  }
}

export interface PageEditorState {
  published: boolean;
  depublished: boolean;
  scheduled: boolean;
  live: Version | null;
}
</script>
