<template>
  <b-container fluid="xl">
    <page-title :description="$t('pageFirmware.pageDescription')" />
    <!-- Operation in progress alert -->
    <alert v-if="isOperationInProgress" variant="info" class="mb-5">
      <p>
        {{ $t('pageFirmware.alert.operationInProgress') }}
      </p>
    </alert>
    <!-- Shutdown server warning alert -->
    <alert v-else-if="!isHostOff" variant="warning" class="mb-5">
      <p class="font-weight-bold mb-1">
        {{ $t('pageFirmware.alert.serverShutdownRequiredBeforeUpdate') }}
      </p>
      {{ $t('pageFirmware.alert.serverShutdownRequiredInfo') }}
      <template v-slot:action>
        <b-btn variant="link" class="text-nowrap" @click="onClickShutDown">
          {{ $t('pageFirmware.alert.shutDownServer') }}
        </b-btn>
      </template>
    </alert>
    <b-row class="mb-4">
      <!-- Firmware on system -->
      <b-col md="10" lg="12" xl="8" class="pr-xl-4">
        <page-section :section-title="$t('pageFirmware.firmwareOnSystem')">
          <b-card-group deck>
            <!-- Current FW -->
            <b-card header-bg-variant="success">
              <template v-slot:header>
                <dl class="mb-0">
                  <dt>{{ $t('pageFirmware.current') }}</dt>
                  <dd class="mb-0">{{ systemFirmwareVersion }}</dd>
                </dl>
              </template>
              <b-row>
                <b-col xs="6">
                  <dl class="my-0">
                    <dt>{{ $t('pageFirmware.bmcStatus') }}</dt>
                    <dd>{{ $t('pageFirmware.running') }}</dd>
                  </dl>
                </b-col>
                <b-col xs="6">
                  <dl class="my-0">
                    <dt>{{ $t('pageFirmware.hostStatus') }}</dt>
                    <dd v-if="hostStatus === 'on'">
                      {{ $t('global.status.on') }}
                    </dd>
                    <dd v-else-if="hostStatus === 'off'">
                      {{ $t('global.status.off') }}
                    </dd>
                    <dd v-else>
                      {{ $t('global.status.notAvailable') }}
                    </dd>
                  </dl>
                </b-col>
              </b-row>
            </b-card>

            <!-- Backup FW -->
            <b-card>
              <template v-slot:header>
                <dl class="mb-0">
                  <dt>{{ $t('pageFirmware.backup') }}</dt>
                  <dd class="mb-0">{{ backupFirmwareVersion }}</dd>
                </dl>
              </template>
              <b-row>
                <b-col xs="6">
                  <dl class="my-0">
                    <dt>{{ $t('pageFirmware.state') }}</dt>
                    <dd>{{ backupFirmwareStatus }}</dd>
                  </dl>
                </b-col>
              </b-row>
            </b-card>
          </b-card-group>
        </page-section>

        <!-- Change to backup image -->
        <page-section :section-title="$t('pageFirmware.changeToBackupImage')">
          <dl class="mb-5">
            <dt>
              {{ $t('pageFirmware.backupImage') }}
            </dt>
            <dd>{{ backupFirmwareVersion }}</dd>
          </dl>
          <b-btn
            v-b-modal.modal-reboot-backup
            type="button"
            variant="primary"
            :disabled="isPageDisabled || !isRebootFromBackupAvailable"
          >
            {{ $t('pageFirmware.changeAndRebootBmc') }}
          </b-btn>
        </page-section>
      </b-col>

      <!-- Update code -->
      <b-col sm="8" xl="4" class="update-code pl-xl-4">
        <page-section :section-title="$t('pageFirmware.updateCode')">
          <b-form @submit.prevent="onSubmitUpload">
            <b-form-group
              :label="$t('pageFirmware.form.uploadLocation')"
              :disabled="isPageDisabled"
            >
              <b-form-radio v-model="isWorkstationSelected" :value="true">
                {{ $t('pageFirmware.form.workstation') }}
              </b-form-radio>
              <b-form-radio v-model="isWorkstationSelected" :value="false">
                {{ $t('pageFirmware.form.tftpServer') }}
              </b-form-radio>
            </b-form-group>

            <!-- Workstation Upload -->
            <template v-if="isWorkstationSelected">
              <b-form-group
                :label="$t('pageFirmware.form.imageFile')"
                label-for="image-file"
              >
                <b-form-text id="image-file-help-block">
                  {{ $t('pageFirmware.form.onlyTarFilesAccepted') }}
                </b-form-text>
                <b-form-file
                  id="image-file"
                  v-model="file"
                  accept=".tar"
                  aria-describedby="image-file-help-block"
                  :browse-text="$t('global.fileUpload.browseText')"
                  :drop-placeholder="$t('global.fileUpload.dropPlaceholder')"
                  :placeholder="$t('global.fileUpload.placeholder')"
                  :disabled="isPageDisabled"
                  :state="getValidationState($v.file)"
                  @input="$v.file.$touch()"
                />
                <b-form-invalid-feedback role="alert">
                  {{ $t('global.form.required') }}
                </b-form-invalid-feedback>
              </b-form-group>
            </template>

            <!-- TFTP Server Upload -->
            <template v-else>
              <b-form-group
                :label="$t('pageFirmware.form.tftpServerIpAddress')"
                label-for="tftp-ip"
              >
                <b-form-input
                  id="tftp-id"
                  v-model="tftpIpAddress"
                  type="text"
                  :state="getValidationState($v.tftpIpAddress)"
                  :disabled="isPageDisabled"
                  @input="$v.tftpIpAddress.$touch()"
                />
                <b-form-invalid-feedback role="alert">
                  {{ $t('global.form.fieldRequired') }}
                </b-form-invalid-feedback>
              </b-form-group>
              <b-form-group
                :label="$t('pageFirmware.form.imageFileName')"
                label-for="tftp-file-name"
              >
                <b-form-input
                  id="tftp-file-name"
                  v-model="tftpFileName"
                  type="text"
                  :state="getValidationState($v.tftpFileName)"
                  :disabled="isPageDisabled"
                  @input="$v.tftpFileName.$touch()"
                />
                <b-form-invalid-feedback role="alert">
                  {{ $t('global.form.fieldRequired') }}
                </b-form-invalid-feedback>
              </b-form-group>
            </template>

            <!-- Info alert -->
            <alert variant="info" class="mt-4 mb-5">
              <p class="font-weight-bold mb-1">
                {{ $t('pageFirmware.alert.updateProcess') }}
              </p>
              <p>{{ $t('pageFirmware.alert.updateProcessInfo') }}</p>
            </alert>
            <b-form-group>
              <b-btn type="submit" variant="primary" :disabled="isPageDisabled">
                {{ $t('pageFirmware.form.uploadAndRebootBmc') }}
              </b-btn>
            </b-form-group>
          </b-form>
        </page-section>
      </b-col>
    </b-row>

    <!-- Modals -->
    <modal-upload @ok="uploadFirmware" />
    <modal-reboot-backup
      :current="systemFirmwareVersion"
      :backup="backupFirmwareVersion"
      @ok="rebootFromBackup"
    />
  </b-container>
</template>

<script>
import { requiredIf } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';

import PageSection from '@/components/Global/PageSection';
import PageTitle from '@/components/Global/PageTitle';
import Alert from '@/components/Global/Alert';
import ModalUpload from './FirmwareModalUpload';
import ModalRebootBackup from './FirmwareModalRebootBackup';

import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
import BVToastMixin from '@/components/Mixins/BVToastMixin';

export default {
  name: 'Firmware',
  components: {
    Alert,
    ModalRebootBackup,
    ModalUpload,
    PageSection,
    PageTitle
  },
  mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin],
  data() {
    return {
      isWorkstationSelected: true,
      file: null,
      tftpIpAddress: null,
      tftpFileName: null,
      timeoutId: null
    };
  },
  computed: {
    hostStatus() {
      return this.$store.getters['global/hostStatus'];
    },
    isHostOff() {
      return this.hostStatus === 'off' ? true : false;
    },
    isOperationInProgress() {
      return this.$store.getters['controls/isOperationInProgress'];
    },
    ...mapGetters('firmware', [
      'backupFirmwareStatus',
      'backupFirmwareVersion',
      'isRebootFromBackupAvailable',
      'systemFirmwareVersion'
    ]),
    isPageDisabled() {
      return !this.isHostOff || this.loading || this.isOperationInProgress;
    }
  },
  watch: {
    isWorkstationSelected: function() {
      this.$v.$reset();
      this.file = null;
      this.tftpIpAddress = null;
      this.tftpFileName = null;
    }
  },
  created() {
    this.startLoader();
    this.$store.dispatch('firmware/getUpdateServiceApplyTime');
    Promise.all([
      this.$store.dispatch('global/getHostStatus'),
      this.$store.dispatch('firmware/getSystemFirwareVersion')
    ]).finally(() => this.endLoader());
  },
  beforeRouteLeave(to, from, next) {
    this.hideLoader();
    this.clearRebootTimeout();
    next();
  },
  validations() {
    return {
      file: {
        required: requiredIf(function() {
          return this.isWorkstationSelected;
        })
      },
      tftpIpAddress: {
        required: requiredIf(function() {
          return !this.isWorkstationSelected;
        })
      },
      tftpFileName: {
        required: requiredIf(function() {
          return !this.isWorkstationSelected;
        })
      }
    };
  },
  methods: {
    uploadFirmware() {
      const startTime = this.$options.filters.formatTime(new Date());
      this.setRebootTimeout(360000); //6 minute timeout
      this.infoToast(
        this.$t('pageFirmware.toast.infoUploadStartTimeMessage', { startTime }),
        this.$t('pageFirmware.toast.infoUploadStartTimeTitle')
      );
      if (this.isWorkstationSelected) {
        this.dispatchWorkstationUpload();
      } else {
        this.dispatchTftpUpload();
      }
    },
    dispatchWorkstationUpload() {
      this.$store
        .dispatch('firmware/uploadFirmware', this.file)
        .then(success =>
          this.infoToast(
            success,
            this.$t('pageFirmware.toast.successUploadTitle')
          )
        )
        .catch(({ message }) => {
          this.errorToast(message);
          this.clearRebootTimeout();
        });
    },
    dispatchTftpUpload() {
      const data = {
        address: this.tftpIpAddress,
        filename: this.tftpFileName
      };
      this.$store
        .dispatch('firmware/uploadFirmwareTFTP', data)
        .then(success =>
          this.infoToast(
            success,
            this.$t('pageFirmware.toast.successUploadTitle')
          )
        )
        .catch(({ message }) => {
          this.errorToast(message);
          this.clearRebootTimeout();
        });
    },
    rebootFromBackup() {
      this.setRebootTimeout();
      this.$store
        .dispatch('firmware/switchFirmwareAndReboot')
        .then(success =>
          this.infoToast(success, this.$t('global.status.success'))
        )
        .catch(({ message }) => {
          this.errorToast(message);
          this.clearRebootTimeout();
        });
    },
    setRebootTimeout(timeoutMs = 60000) {
      // Set a timeout to disable page interactions while
      // an upload or BMC reboot is in progress
      this.startLoader();
      this.timeoutId = setTimeout(() => {
        this.endLoader();
        this.infoToast(
          this.$t('pageFirmware.toast.infoRefreshApplicationMessage'),
          this.$t('pageFirmware.toast.infoRefreshApplicationTitle')
        );
      }, timeoutMs);
    },
    clearRebootTimeout() {
      if (this.timeoutId) {
        clearTimeout(this.timeoutId);
        this.endLoader();
      }
    },
    onSubmitUpload() {
      this.$v.$touch();
      if (this.$v.$invalid) return;
      this.$bvModal.show('modal-upload');
    },
    onClickShutDown() {
      this.$bvModal
        .msgBoxConfirm(this.$t('pageFirmware.modal.serverShutdownMessage'), {
          title: this.$t('pageFirmware.modal.serverShutdownWillCauseOutage'),
          okTitle: this.$t('pageFirmware.modal.shutDownServer'),
          okVariant: 'danger'
        })
        .then(shutdownConfirmed => {
          if (shutdownConfirmed)
            this.$store.dispatch('controls/hostSoftPowerOff');
        });
    }
  }
};
</script>

<style lang="scss" scoped>
.update-code {
  border-left: none;
  @include media-breakpoint-up(xl) {
    border-left: 1px solid gray('300');
  }
}
</style>
