<template>
  <div class="install-container">
    <section class="top">
      <header>
        <h2>Dependencies</h2>
      </header>

      <div class="body">
        <div class="container install-cmd-container">
          <CopyButton :text="installCmd" />
          <pre><code v-html="highlightedInstallCmd" /></pre>
        </div>

        <div class="buttons install-btn" v-if="installCmd?.length">
          <button type="button"
                  class="btn btn-default"
                  :disabled="installRunning"
                  @click="installExtension">
            <i class="fas fa-download" /> Install
          </button>
        </div>
      </div>
    </section>

    <section class="bottom" v-if="installRunning || installOutput">
      <header>
        <h2>Output</h2>
      </header>

      <div class="body">
        <div class="container install-output" ref="installOutput">
          <CopyButton :text="installOutput" />
          <pre><code v-text="installOutput" /><div
                     class="loading-container"
                     v-if="installRunning">
            <Loading />
          </div></pre>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
import 'highlight.js/lib/common'
import 'highlight.js/styles/stackoverflow-dark.min.css'
import hljs from "highlight.js"
import CopyButton from "@/components/elements/CopyButton"
import Loading from "@/components/Loading"
import Utils from "@/Utils"

export default {
  name: "Install",
  mixins: [Utils],
  emit: ['install-start', 'install-end'],
  components: {
    CopyButton,
    Loading,
  },

  props: {
    extension: {
      type: Object,
      required: true,
    },
  },

  data() {
    return {
      installRunning: false,
      installOutput: null,
      pendingCommands: 0,
    }
  },

  computed: {
    installCmd() {
      const cmd = this.extension.deps.install_cmd.join('\n').trim()
      return cmd?.length ? cmd : null
    },

    highlightedInstallCmd() {
      return (
        this.installCmd ?
        hljs.highlight(
          'bash',
          this.extension.deps.install_cmd
          .map((cmd) => `$ ${cmd}`)
          .join('\n')
          .trim()
        ).value :
        '# No extra installation steps required'
      )
    },
  },

  methods: {
    wsProcess(path) {
      try {
        const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'
        const url = `${protocol}://${location.host}${path}`
        const ws = new WebSocket(url)

        ws.onmessage = this.onMessage
        ws.onerror = this.onError
        ws.onclose = this.onClose
      } catch (err) {
        console.error('Websocket initialization error')  // TODO notify
        console.error(err)
        return
      }
    },

    onMessage(msg) {
      if (!this.installOutput)
        this.installOutput = ''

      this.installOutput += msg.data
    },

    onClose() {
      this.installRunning = false
      this.$emit('install-end', this.extension)
    },

    onError(error) {
      console.error('Websocket error')  // TODO notify
      console.error(error)
    },

    installExtension() {
      this.installRunning = true
      this.installOutput = ''
      this.$emit('install-start', this.extension)

      const cmd = (this.extension.deps.install_cmd || []).join(';\n')
      this.request('shell.exec', {
        cmd: cmd,
        ws: true,
      }).then((output) => {
        this.wsProcess(output.ws_path)
      }).catch((err) => {
        console.error(err)  // TODO notify
      })
    },
  },

  mounted() {
    this.$watch('installOutput', () => {
      this.$nextTick(() => {
        this.$refs.installOutput.focus()
        this.$refs.installOutput.scrollTop = this.$refs.installOutput.scrollHeight
      })
    })
  },
}
</script>

<style lang="scss" scoped>
@import "common.scss";

$header-height: 3.5em;

.install-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;

  section {
    &.top {
      height: 33.3333% !important;
    }

    &.bottom {
      height: 66.6666% !important;
    }

    header {
      height: $header-height;
      padding-left: 0.5em;
      border-top: 1px solid $border-color-1;
      border-bottom: 1px solid $border-color-1;
    }

    .body {
      height: calc(100% - #{$header-height});
      display: flex;
      flex-direction: column;
      padding: 1em;
    }

    h2 {
      font-size: 1.3em;
      opacity: 0.9;
    }
  }

  .container {
    width: 100%;
    height: 100%;
    position: relative;
    display: flex;
    flex-direction: column;
  }

  pre {
    height: 100%;
    position: relative;
    border-radius: 1em;
  }

  .install-btn {
    width: 100%;
    margin-top: 1em;
    display: flex;
    justify-content: right;

    button {
      border-radius: 0.5em;
      margin-right: 0.5em;
    }
  }

  .loading-container {
    width: 100%;
    position: relative;

    :deep(.loading) {
      background: none;
    }
  }
}
</style>
