<template>
  <div>
    <edit-page-top
      :breads="breads"
      :show-submit="initialLoad"
      :disable-submit="!canEdit && initialLoad"
      :show-copy="id > 0 && initialLoad"
      :show-delete="id > 0 && initialLoad"
      :submit-loading="loading && initialLoad"
      :copy-link="copyLink"
      :small-copy="true"
      :small-delete="true"
      @submit="submit"
      @delete="deleteStager"
    >
      <template #extra-stuff>
        <tooltip-button
          v-if="id > 0 && initialLoad && isDownload(stager)"
          color="success"
          icon="fa-download"
          text="Download"
          @click="download(stager)"
        />
        <tooltip-button
          v-if="id > 0 && initialLoad && isOneLiner(stager)"
          color="success"
          icon="fa-paperclip"
          text="Copy To Clipboard"
          @click="copy(stager)"
        />
      </template>
    </edit-page-top>
    <div class="headers">
      <h3>{{ mode }} Stager</h3>
    </div>
    <error-state-alert
      v-if="errorState"
      :resource-id="id"
      resource-type="stager"
    />
    <v-card v-else style="padding: 10px">
      <info-viewer class="info-viewer" :info="stagerInfo" />
      <v-autocomplete
        v-model="selectedTemplate"
        :items="stagerTemplateIds"
        :loading="!initialLoad"
        density="compact"
        variant="outlined"
        label="Type"
        :readonly="!canEdit"
      />
      <v-row v-if="selectedTemplate">
        <v-col cols="6">
          <v-text-field
            v-model="stager.name"
            variant="outlined"
            density="compact"
            label="Name"
            :readonly="!canEdit"
          />
        </v-col>
        <v-col cols="6">
          <v-list-subheader>
            A name for the stager. Leave blank for an autogenerated name.
          </v-list-subheader>
        </v-col>
      </v-row>
      <general-form
        v-if="initialLoad"
        :key="selectedTemplate"
        ref="generalform"
        v-model="form"
        :options="stagerOptions"
        :priority="formPriorities"
        :readonly="!canEdit"
      />
    </v-card>
  </div>
</template>

<script>
import InfoViewer from "@/components/InfoViewer.vue";
import GeneralForm from "@/components/GeneralForm.vue";
import ErrorStateAlert from "@/components/ErrorStateAlert.vue";
import EditPageTop from "@/components/EditPageTop.vue";
import * as downloadApi from "@/api/download-api";
import CopyMixin from "@/mixins/copy-stager";
import TooltipButton from "@/components/TooltipButton.vue";
import { useStagerStore } from "@/stores/stager-module";
import * as stagerApi from "@/api/stager-api";

export default {
  name: "StagerEdit",
  components: {
    InfoViewer,
    GeneralForm,
    ErrorStateAlert,
    EditPageTop,
    TooltipButton,
  },
  mixins: [CopyMixin],
  inject: ["snack", "confirm"],
  data() {
    return {
      stager: { options: {} },
      stagerTemplate: { options: {} },
      selectedTemplate: "",
      form: {},
      loading: false,
      formPriorities: ["Listener", "Language"],
      errorState: false,
      initialLoad: false,
    };
  },
  computed: {
    stagerStore() {
      return useStagerStore();
    },
    stagerTemplateIds() {
      return this.stagerStore.templateIds;
    },
    isNew() {
      return this.$route.name === "stagerNew";
    },
    isCopy() {
      return this.$route.query.copy === "true";
    },
    mode() {
      if (this.isCopy) return "Copy";
      if (this.isNew) return "New";
      return "View";
    },
    canEdit() {
      return true;
    },
    id() {
      return this.isCopy ? 0 : this.$route.params.id || this.$route.query.id;
    },
    copyLink() {
      if (this.id > 0)
        return { name: "stagerNew", query: { copy: true, id: this.id } };
      return {};
    },
    stagerInfo() {
      if (!this.stagerTemplate) return {};
      const a = this.stagerTemplate;
      return {
        authors: a.authors,
        description: a.description,
        comments: a.comments,
      };
    },
    stagerOptions() {
      if (!this.isNew || this.isCopy) {
        // if it's not new, set the option values from the existing stager
        const options = {};
        const templateOptions =
          (this.stagerTemplate && this.stagerTemplate.options) || {};
        const stagerOpts =
          this.stager && this.stager.options ? this.stager.options : {};
        Object.keys(stagerOpts).forEach((key) => {
          const base = templateOptions[key] ? { ...templateOptions[key] } : {};
          options[key] = base;
          options[key].value = stagerOpts[key];
        });
        return options;
      }

      // if it's new, use the defaults from the template
      const templateOptions =
        (this.stagerTemplate && this.stagerTemplate.options) || {};
      // Create a shallow clone so we don't mutate the template object directly
      const options = Object.keys(templateOptions).reduce((acc, k) => {
        acc[k] = { ...templateOptions[k] };
        return acc;
      }, {});
      if (Object.keys(options).length === 0) return {};

      // if the listener query param is set, set the listener to that (when present)
      if (this.$route.query.listener && options.Listener) {
        options.Listener.value = this.$route.query.listener;
      }
      return options;
    },
    breads() {
      return [
        {
          title: "Stagers",
          disabled: false,
          to: "/stagers",
          exact: true,
        },
        {
          title: this.breadcrumbName,
          disabled: true,
          to: `/stagers/${this.id}`,
        },
      ];
    },
    breadcrumbName() {
      if (this.isCopy) return "New";
      if (this.stager.name) return this.stager.name;
      if (this.id) return this.id;
      return "New";
    },
  },
  watch: {
    /**
     * When the type dropdown changes, we get the options for the new type.
     */
    selectedTemplate: {
      async handler(val) {
        const a = await stagerApi
          .getStagerTemplate(val)
          .catch((err) => this.snack.error(`Error: ${err}`));
        if (a) {
          this.stagerTemplate = a;
          this.initialLoad = true;
        }
      },
    },
    id(val) {
      if (val) {
        this.getStager(val);
      }
    },
  },
  mounted() {
    this.stagerStore.getStagerTemplates();

    if (!this.isNew || this.isCopy) {
      // using the route param id instad of this.id
      // since this.id is 0 for copies.
      this.getStager(this.$route.params.id || this.$route.query.id);
    }

    if (this.$route.query.template) {
      this.selectedTemplate = this.$route.query.template;
    }
  },
  methods: {
    async submit() {
      if (this.loading) return;
      const valid = await this.$refs.generalform.validate();
      if (!valid) return;

      this.loading = true;
      if (this.id > 0) {
        try {
          await stagerApi.updateStager(this.id, {
            name: this.stager.name,
            options: this.form,
          });
          this.snack.success("Stager updated");
          this.loading = false;
          this.getStager(this.id);
        } catch (err) {
          this.snack.error(`Error: ${err}`);
          this.loading = false;
        }
      } else {
        stagerApi
          .createStager(
            this.selectedTemplate,
            this.stager.name || this.randomName(),
            this.form,
          )
          .then(({ id }) => {
            this.snack.success("Stager created");
            this.loading = false;
            this.$router.push({ name: "stagerEdit", params: { id } });
          })
          .catch((err) => {
            this.snack.error(`Error: ${err}`);
            this.loading = false;
          });
      }
    },
    async deleteStager() {
      if (
        await this.confirm(
          "Delete",
          `Are you sure you want to delete stager ${this.form.StarkillerName}?`,
          { color: "red" },
        )
      ) {
        try {
          await this.stagerStore.deleteStager(this.id);
          this.$router.push({ name: "stagers" });
        } catch (err) {
          this.snack.error(`Error: ${err}`);
        }
      }
    },
    getStager(id) {
      stagerApi
        .getStager(id)
        .then((data) => {
          this.stager = data;
          this.selectedTemplate = data.template;
        })
        .catch((err) => {
          console.error(err);
          this.snack.error(`Failed to load resource: ${err}`);
          this.errorState = true;
        });
    },
    randomName() {
      return (Math.random() + 1).toString(36).substring(7);
    },
    isDownload(stager) {
      return stager.downloads && stager.downloads.length > 0;
    },
    isOneLiner(stager) {
      return stager.one_liner;
    },
    // later on we could display multiple files, but at the moment,
    // i think it makes sense to just get the last one.
    async copy(stager) {
      const lastIndex = stager.downloads.length - 1;
      return this.copyStager(
        await downloadApi.getDownloadAsText(stager.downloads[lastIndex].id),
      );
    },
    async download(stager) {
      const lastIndex = stager.downloads.length - 1;
      return downloadApi.getDownload(stager.downloads[lastIndex].id);
    },
  },
};
</script>

<style></style>
