<script>
import { cleanForNew } from '@/plugins/steve/normalize';
import CreateEditView from '@/mixins/create-edit-view';
import ResourceYaml from '@/components/ResourceYaml';
import {
  MODE, _VIEW, _EDIT, _CLONE, _STAGE,
  EDIT_YAML, _FLAGGED, _CREATE
} from '@/config/query-params';
import { NAMESPACE } from '@/config/types';

// Components can't have asyncData, only pages.
// So you have to call this in the page and pass it in as a prop.
export async function asyncData(ctx) {
  const { store, params, route } = ctx;
  const { resource, namespace, id } = params;

  const hasCustomDetail = store.getters['type-map/hasCustomDetail'](resource);
  const hasCustomEdit = store.getters['type-map/hasCustomEdit'](resource);

  // There are 5 "real" modes: view, create, edit, stage, clone
  // which later map to 3 logical/page modes: view, create, edit (stage and clone are "create")
  const realMode = route.query.mode || _VIEW;
  const schema = store.getters['cluster/schemaFor'](resource);

  let fqid = id;

  if ( schema.attributes.namespaced && namespace ) {
    fqid = `${ namespace }/${ fqid }`;
  }

  const obj = await store.dispatch('cluster/find', { type: resource, id: fqid });

  const forNew = realMode === _CLONE || realMode === _STAGE;
  const model = await store.dispatch('cluster/clone', { resource: obj });

  if ( forNew ) {
    cleanForNew(model);
  }

  if ( model.applyDefaults ) {
    model.applyDefaults(ctx, realMode);
  }

  let mode = realMode;

  if ( realMode === _STAGE || realMode === _CLONE ) {
    mode = _CREATE;
  }

  const asYaml = (route.query[EDIT_YAML] === _FLAGGED) || (mode === _VIEW && !hasCustomDetail) || (mode !== _VIEW && !hasCustomEdit);
  let yaml = null;

  const link = obj.hasLink('rioview') ? 'rioview' : 'view';

  yaml = (await obj.followLink(link, { headers: { accept: 'application/yaml' } })).data;

  /*******
   * Important: these need to be declared below as props too
   *******/
  const out = {
    hasCustomDetail,
    hasCustomEdit,
    schema,
    resource,
    model,
    asYaml,
    yaml,
    originalModel: obj,
    mode,
    realMode
  };
  /*******
   * Important: these need to be declared below as props too
   *******/

  return out;
}

export const watchQuery = [MODE, EDIT_YAML];

export default {
  components: { ResourceYaml },
  mixins:     { CreateEditView },

  props: {
    hasCustomDetail: {
      type:    Boolean,
      default: null,
    },
    hasCustomEdit: {
      type:    Boolean,
      default: null,
    },
    schema: {
      type:    Object,
      default: null,
    },
    resource: {
      type:    String,
      default: null,
    },
    model: {
      type:    Object,
      default: null,
    },
    asYaml: {
      type:    Boolean,
      default: null,
    },
    yaml: {
      type:    String,
      default: null,
    },
    originalModel: {
      type:    Object,
      default: null,
    },
    mode: {
      type:    String,
      default: null
    },
    realMode: {
      type:    String,
      default: null
    }
  },

  data() {
    if (this.hasCustomDetail) {
      this.$store.getters['type-map/importDetail'](this.resource)().then((component) => {
        this.importedDetailComponent = component.default;
      });
    }

    if (this.hasCustomEdit) {
      this.$store.getters['type-map/importEdit'](this.resource)().then((component) => {
        this.importedEditComponent = component.default;
      });
    }

    return {
      isCustomYamlEditor:      false,
      currentValue:            this.value,
      detailComponent:         this.$store.getters['type-map/importDetail'](this.resource),
      importedDetailComponent: null,
      editComponent:           this.$store.getters['type-map/importEdit'](this.resource),
      importedEditComponent:   null,
    };
  },

  computed: {
    isView() {
      return this.mode === _VIEW;
    },

    isEdit() {
      return this.mode === _EDIT;
    },

    showEditAsYaml() {
      return this.isEdit && !this.importedEditComponent?.isYamlEditor;
    },

    doneRoute() {
      const name = this.$route.name.replace(/(-namespace)?-id$/, '');

      return name;
    },

    doneParams() {
      return this.$route.params;
    },

    parentLink() {
      const name = this.doneRoute;
      const params = this.doneParams;
      const out = this.$router.resolve({ name, params }).href;

      return out;
    },

    showComponent() {
      if ( this.isView && this.hasCustomDetail ) {
        return this.detailComponent;
      } else if ( !this.isView && this.hasCustomEdit ) {
        return this.editComponent;
      }

      return null;
    },

    typeDisplay() {
      return this.$store.getters['type-map/singularLabelFor'](this.schema);
    },

    namespaceSuffixOnCreate() {
      return this.resource !== NAMESPACE;
    }
  },

  methods: {
    showActions() {
      this.$store.commit('action-menu/show', {
        resources: this.originalModel,
        elem:      this.$refs.actions,
      });
    },

    goBack() {
      window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/');
    },

    navigateToEditAsYaml() {
      this.$router.push({ query: { ...this.$route.query, [EDIT_YAML]: _FLAGGED } });
    },
  }
};
</script>

<template>
  <div>
    <template v-if="asYaml">
      <ResourceYaml
        :obj="model"
        :value="yaml"
        :done-route="doneRoute"
        :parent-route="doneRoute"
        :parent-params="doneParams"
        :has-edit-as-form="hasCustomEdit"
      />
    </template>
    <template v-else>
      <header>
        <h1 v-trim-whitespace>
          <span v-if="realMode === 'edit'">Edit {{ typeDisplay }}:&nbsp;</span>
          <span v-else-if="realMode === 'stage'">Stage from {{ typeDisplay }}:&nbsp;</span>
          <span v-else-if="realMode === 'clone'">Clone from {{ typeDisplay }}:&nbsp;</span>
          <nuxt-link
            v-else
            v-trim-whitespace
            :to="parentLink"
          >
            {{ typeDisplay }}:&nbsp;
          </nuxt-link>{{ originalModel.nameDisplay }}
        </h1>
        <div v-if="isView" class="actions">
          <button ref="actions" type="button" class="btn btn-sm role-multi-action actions" @click="showActions">
            <i class="icon icon-actions" />
          </button>
        </div>
        <div v-if="showEditAsYaml" class="actions">
          <button class="btn bg-primary" @click="navigateToEditAsYaml">
            Edit as YAML
          </button>
        </div>
      </header>
      <component
        :is="showComponent"
        v-model="model"
        :original-value="originalModel"
        :done-route="doneRoute"
        :done-params="doneParams"
        :parent-route="doneRoute"
        :parent-params="doneParams"
        :namespace-suffix-on-create="namespaceSuffixOnCreate"
        :type-label="typeDisplay"
        :mode="mode"
        :value="model"
        :obj="model"
        :yaml="yaml"
      />
    </template>
  </div>
</template>

<style lang='scss' scoped>
  .flat {
    border-collapse: collapse;
    table-layout: fixed;
    width: 100%;
    & th{
      padding-bottom: 1rem;
      text-align: left;
      font-weight: normal;
      color: var(--secondary);
    }

    & :not(THEAD) tr{
      border-bottom: 1px solid var(--border);

      & td {
        padding: 10px 0 10px 0;
      }
    }
    & tr td:last-child, th:last-child{
      text-align: right;
    }

    & tr td:first-child, th:first-child{
      text-align: left;
      margin-left: 15px;
    }

    & .click-row a{
      color: var(--input-text);
    }

    & .click-row:hover{
      @extend .faded;
    }

    & .faded {
      opacity: 0.5
    }
  }
  .detail-top{
    display: flex;
    flex-wrap: wrap;
    background: var(--box-bg);
    border: solid thin var(--border);
    border-radius: var(--border-radius);

    & > * {
      margin-right: 20px;
      padding: 10px 0 10px 0;
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: flex-start;

      &:not(:last-child){
      border-right: 1px solid var(--border);
      }

      & >:not(:first-child){
        color: var(--input-label);
        padding: 3px;
      }
    }
  }
</style>
