<template>
  <div class="disk">
    <el-select
      class="ui-custom-select"
      :placeholder="$t('set.configuration.disks.selectDisk')"
      :disabled="true"
      value=""
    >
      <!-- <el-option :label="$t('set.configuration.disks.inputPath')" :value="ConfigTypes.INPUT_PATH"></el-option> -->
      <el-option :label="$t('set.configuration.disks.selectDisk')" value=""></el-option>
    </el-select>

    <template>
      <div class="disk-select">
        <el-select
          @change="setTmpDisk"
          :value="targetprep"
          size="mini"
          :placeholder="$t('common.startSelect')"
          class="ui-custom-select"
          filterable
        >
          <el-option
            v-for="disk in formatedDisks"
            :key="disk.kname + '_tmp'"
            :label="`${disk.formatedDisk} | ${disk.sizeString}`"
            :value="'/dev/' + disk.name"
          >
            <span style="float: left">{{ disk.formatedDisk }}</span>
            <span style="float: right; color: #8492a6; font-size: 13px">
              {{ disk.sizeString }}
            </span>
          </el-option>
        </el-select>
      </div>
    </template>
  </div>
</template>

<script lang="ts">
import { niceBytes } from '@/utils'
import { Vue, Component, Prop, Model } from 'vue-property-decorator'

@Component({
  name: 'TargetStashLocationDev'
})
export default class extends Vue {
  @Prop() isWindows: boolean
  @Prop() targetDisks: any[]
  @Prop() takenTargetDisks: { [key: string]: boolean }

  @Model('tmp') readonly targetprep: string
  type: 'current' | 'new' = 'current'

  get formatedDisks() {
    return this.targetDisks
      .filter((disk) => {
        return (!this.takenTargetDisks[disk.name] || disk.name === this.targetprep)
      })
      .map((disk) => {
        const formatedDisk = this.isWindows ? this.$t('common.disk') + ' ' + disk.name : disk.name
        return {
          ...disk,
          sizeString: niceBytes(disk.size),
          formatedDisk
        }
      })
      .sort((d1, d2) => d1.kname.localeCompare(d2.kname))
  }

  setTmpDisk(val: string) {
    this.$emit('tmp', val)
  }
}
</script>

<template>
  <loader v-if="!sourceBootDisk || !targetBootDisk" />
	<div v-else class="disk-configure-container">
    <row-disks label="">
      <div class="type" slot="sourceDiskConfig">
        {{ $t('common.source')}}
      </div>
      <div class="type" slot="targetDiskConfig">
        {{$t('common.target')}}
      </div>
    </row-disks>
    <row-disks v-if="pairsCreated" :label="$t('set.configuration.disks.bootDisk')">
      <div slot="sourceDiskConfig">
        <current
          :isBoot="true"
          :isBootDisk="true"
          :name="sourceBoot"
          :size="sourceBootDisk.size"
          :selected="form.diskmap[sourceBootDisk.kname]['selected']"
          :isWindows="isWindows"
          @selected="setSelected($event, sourceBootDisk.kname)"
          @show-disk="showDisk($event, sourceBootDisk.kname)"
			  ></current>
      </div>
      <div slot="targetDiskConfig">
        <new
          :disabled="true"
          :minSize="sourceBootDisk.size"
          :targetDisks="[targetBootDisk]"
          :takenTargetDisks="{}"
          :target="targetBoot"
          :isWindows="isWindows"
          :isBootRow="true"
          :hasPartitions="sourceBootDisk.hasPartitions"
          :reconfig="form.diskmap[sourceBootDisk.kname]['reconfig']"
          @reconfigTarget="reconfigTarget($event, sourceBootDisk.kname)"
			  />
      </div>
    </row-disks>
    <div class="error" v-show="bootError">{{ $t('set.configuration.disks.bootError')}}</div>
    <template v-if="pairsCreated">
      <row-disks
        v-for="(disk, idx) in sourceDisks"
        :key="disk.name"
        :label="idx === 0 ? $t('set.configuration.disks.dataDisks') : ''"
        :isDataDisk="true"
        :isLastDataDisk="idx === (sourceDisks.length - 1)"
        :isFirstDataDisk="idx === 0"
      >
        <div slot="sourceDiskConfig">
          <current
            :boot="disk.boot"
            :name="disk.name"
            :size="disk.size"
            :disabled="isSourceDiskDisabled(disk.name)"
            :selected="form.diskmap[disk.name]['selected']"
            :isWindows="isWindows"
            @selected="setSelected($event, disk.name)"
            @show-disk="showDisk($event, disk.kname)"
          />
        </div>
        <div slot="targetDiskConfig">
          <new
            :isWindows="isWindows"
            :disabled="!form.diskmap[disk.name]['selected']"
            :minSize="disk.size"
            :targetDisks="targetDisks"
            :takenTargetDisks="takenTargetDisks"
            :isBootRow="disk.boot"
            :target="form.diskmap[disk.name]['target']"
            @selected="selectTarget($event, disk.name)"
            :hasPartitions="disk.hasPartitions"
            :reconfig="form.diskmap[disk.name]['reconfig']"
            @reconfigTarget="reconfigTarget($event, disk.name)"
          />
        </div>
      </row-disks>
    </template>
    <row-disks :isLogDisk="true" :label="$t('set.configuration.disks.log')">
      <div slot="sourceDiskConfig" v-if="!isWindows">
        <log
          v-model="form.cowConfig"
          :disks="sourceDisks"
          :busyDisks="takenSourceDisks"
          :isWindows="isWindows"
        />
      </div>
      <div
        class="link"
        style="width: fit-content;"
        slot="logdiskCalculator"
        @click="openCalcDialog"
      >
        {{ $t('set.configuration.disks.calculate') }}
      </div>
      <div slot="targetDiskConfig">
        <Tmp
          v-if="isShowTmp"
          v-model="form.targetprep"
          :targetDisks="targetDisks"
          :takenTargetDisks="takenTargetDisks"
          :isWindows="isWindows"
        />
        <TargetStashLocationDev
          v-else
          v-model="form.targetStashLocationDev"
          :targetDisks="targetDisks"
          :takenTargetDisks="takenTargetDisks"
        />
      </div>
    </row-disks>
	</div>
</template>

<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'
import Current from './current.vue'
import New from './new.vue'
import Tmp from './tmp.vue'
import Log from './log.vue'
import TargetStashLocationDev from './TargetStashLocationDev.vue'
import UiButton from '@/components/ui-kit/Button/Migrate/Default/UiButton_F.vue'
import { DiskMapPayload, CowConfig, CowConfigTypes, GroupDiskmapPayload } from '@/@types/set'
import { SetModule } from '@/store/modules/set'
import { FProtsetConfig } from '@/@types/frontend/index'
import RowDisks from '../common/RowDisks.vue'
import Loader from '@/components/ui-kit/Loader/index.vue'
import { UnitModule } from '@/store/modules/unit'

interface DisksPair {
  source: string
  target: string
  selected: boolean
  reconfig: boolean
}

export interface FormNew {
  diskmap: {
    [key: string]: DisksPair
  }
  targetStashLocationDev: string
  targetprep: {
    tmpdisk: string
    ramboot: boolean
  }
  cowConfig: CowConfig
}

@Component({
  name: 'DiskConfigure',
  components: {
    Current,
    New,
    Tmp,
    Log,
    UiButton,
    TargetStashLocationDev,
    RowDisks,
    Loader
  }
})
export default class extends Vue {
  @Prop() set: FProtsetConfig.FProtsetConfig

  pairsCreated = false
  isShowTmp = false
  isDialogCaclVisible = false

  form: FormNew = {
	  diskmap: {},
    targetStashLocationDev: '',
	  targetprep: {
      tmpdisk: '',
      ramboot: false
    },
    cowConfig: {
      type: CowConfigTypes.SELECT_DISK,
      dst: ''
    }
	}

  prepair: {[key: string] : string} = {}

  created() {
    const { diskmap } = this.form
    this.sourceDisks.forEach((disk) => {
      diskmap[disk.name] = {
        source: disk.name,
        target: '',
        selected: false,
        reconfig: false
      }
    })
	  const { targetprep, diskmap: config, cowConfig, targetStashLocationDev } = this.set.config.diskConfig

	  if (targetprep) {
      const targetprepCopy = {
        ...targetprep,
        tmpdisk: targetprep.ramboot ? 'bootToRam' : targetprep.tmpdisk
      }

      this.$set(this.form, 'targetprep', targetprepCopy ?? {})
    }

    if (cowConfig) {
      this.$set(this.form, 'cowConfig', cowConfig ?? {})
    }

    if (targetStashLocationDev) {
      this.$set(this.form, 'targetStashLocationDev', targetStashLocationDev)
    }

    if (config) {
      Object.values(config).reduce((acc, pair) => {
        diskmap[pair.sourceKname] = {
          source: pair.sourceKname,
          target: pair.targetKname,
          reconfig: Boolean(pair.reconfig?.option),
          selected: true
        }

        acc[pair.sourceKname] = pair.targetKname
        return acc
      }, {})
    }

    const bootPair: any = {
      source: this.sourceBoot,
      target: this.targetBoot,
      selected: true,
      reconfig: diskmap[this.sourceBoot]?.reconfig || false
    }

    diskmap[this.sourceBoot] = bootPair
    this.$set(this.form, 'diskmap', diskmap)
    this.pairsCreated = true
  }

  get diskmap() {
	  return this.form.diskmap
  }

  get selectedDisks() {
	  return Object.values(this.diskmap)
      .filter((disk) => disk.selected)
      .map((disk) => {
        return { source: disk.source, target: disk.target, reconfig: { option: Number(disk.reconfig) as 0 | 1 } }
      })
  }

  async saveDiskConfig() {
    try {
      const diskNoTarget = this.selectedDisks.find((d) => !d.target)
      const isNoValidPath = this.form.cowConfig.type === CowConfigTypes.INPUT_PATH && !this.form.cowConfig.dst.startsWith('/')
      const isNoLogDisk = this.form.cowConfig.type === CowConfigTypes.SELECT_DISK && !this.form.cowConfig.dst
      const isNoTargetStashLocationDev = this.form.targetStashLocationDev === ''

      // проверяем выбраны ли диски для таргета
      if (diskNoTarget) {
        this.$message({
          message: this.$t('set.configuration.disks.noTarget').toString(),
          type: 'error',
          duration: 1500,
           showClose: true
        })
        return
      }

      if (isNoLogDisk) {
        this.$message({
          message: this.$t('set.configuration.disks.noLogDisk').toString(),
          type: 'error',
          duration: 1500,
           showClose: true
        })
        return
      }

      // проверяем корректно ли введен путь для журнального диска
      if (isNoValidPath) {
        this.$message({
          message: this.$t('set.configuration.disks.invalidPath').toString(),
          type: 'error',
          duration: 1500,
           showClose: true
        })
        return
      }

      if (isNoTargetStashLocationDev) {
        this.$message({
          message: this.$t('set.configuration.disks.noLogDisk').toString(),
          type: 'error',
          duration: 1500,
           showClose: true
        })
        return
      }

      // изменеяем таргет диск в зависимости от опции бут ту рам
      const targetprepCopy = {
        ...this.form.targetprep,
        tmpdisk: this.form.targetprep.ramboot ? '' : this.form.targetprep.tmpdisk
      }

      const diskMapPayload: DiskMapPayload = {
        id: this.set.id,
        diskconfig: {
          diskmap: this.selectedDisks,
          targetprep: targetprepCopy,
          cowConfig: this.form.cowConfig,
          targetStashLocationDev: this.form.targetStashLocationDev
        }
      }

      const payload: GroupDiskmapPayload = {
        protGroupId: parseInt(this.$route.params.groupId),
        disksConfig: [diskMapPayload]
      }

      await SetModule.diskMap(payload)
      return true
    } catch (err) {
      console.log(err)
    }
  }

  get isUefi() {
    return false
  }

  get sourceBoot() {
	  return this.set.source.disks.find((d) => d.isBoot).kname
  }

  get targetBoot() {
    return this.set.target.disks.find((d) => d.isBoot).kname
  }

  get sourceBootDisk() {
    const disk = this.set.source.disks.find((d) => d.isBoot)

    return { ...disk, name: disk.kname }
  }

  get bootDiskRelated() {
    return this.sourceBootDisk.relatedDisks?.reduce((acc, d) => {
      acc[d] = true
      return acc
    }, {}) ?? {}
  }

  get targetBootDisk() {
    const disk = this.set.target.disks.find((d) => d.isBoot)

    return { ...disk, name: disk.kname }
  }

  get bootError() {
    return this.sourceBootDisk.size > this.targetBootDisk.size
  }

  get sourceDisks() {
    return this
      .filterDisks(this.set.source.disks, this.sourceBoot)
      .sort((d1, d2) => d1.kname.localeCompare(d2.kname))
  }

  get targetDisks() {
    return this.filterDisks(this.set.target.disks, this.targetBoot)
  }

  filterDisks(disks: FProtsetConfig.Disk[], boot: string) {
    return disks
	    .map((disk) => {
	      return {
	        ...disk,
	        consumed: disk.size,
	        name: disk.kname,
	        boot: disk.isBoot
	      }
	    })
      .filter((d) => !d.boot)
  }

  setSelected(payload: boolean, source: string) {
    const diskmap = { ...this.diskmap }
    let pair = diskmap[source]
    const linkedDisks = this.sourceBoot === source
      ? this.sourceBootDisk.relatedDisks
      : this.sourceDisks.find((d) => d.kname === source)?.relatedDisks

    if (pair) {
      pair = { ...pair, ...{ selected: payload } }
    }

    diskmap[source] = pair

    if (linkedDisks) {
      linkedDisks.forEach((d) => {
        let pair = diskmap[d]
        pair = { ...pair, ...{ selected: payload } }
        diskmap[d] = pair
      })
    }

    this.$set(this.form, 'diskmap', diskmap)
  }

  selectTarget(target: string, source: string) {
    const diskmap = { ...this.diskmap }
    let pair = diskmap[source]

    if (pair) {
      pair = { ...pair, ...{ target } }
    }

    diskmap[source] = pair

    this.$set(this.form, 'diskmap', diskmap)
  }

  reconfigTarget(reconfig: boolean, source: string) {
    const diskmap = { ...this.diskmap }
    let pair = diskmap[source]

    if (pair) {
      pair = { ...pair, ...{ reconfig } }
    }

    diskmap[source] = pair

    this.$set(this.form, 'diskmap', diskmap)
  }

  get takenTargetDisks() {
	  const accs = Object.values(this.diskmap).reduce((acc, disk) => {
      acc[disk.target] = true
      return acc
    }, {})

    if (!this.form.targetprep.ramboot && this.form.targetprep.tmpdisk) {
      accs[this.form.targetprep.tmpdisk] = true
    }

    if (this.form.targetStashLocationDev) {
      accs[this.form.targetStashLocationDev] = true
    }

    return accs
  }

  get takenSourceDisks() {
	  const accs = Object.values(this.diskmap).reduce((acc, disk) => {
      if (disk.selected) {
        acc[disk.source] = true
      }
      return acc
    }, {})

    if (this.form.cowConfig.dst) {
      accs[this.form.cowConfig.dst] = true
    }

    return accs
  }

  showDisk(payload: any, diskName: string) {
	  this.$emit('show-disk', diskName)
  }

  get isWindows() {
    return this.set.source.os.toLocaleLowerCase().includes('windows')
  }

  isSourceDiskDisabled(name: string) {
    const isBlockedByCow = (this.takenSourceDisks[name] || this.takenSourceDisks['/dev/' + name]) && !this.form.diskmap[name].selected
    const isRelatedWithBoot = this.bootDiskRelated[name]

    return Boolean(isBlockedByCow) || Boolean(isRelatedWithBoot)
  }

  openCalcDialog() {
    UnitModule.updateUnitModals({
      ...UnitModule.unitModals,
      calcLogdiskDialog: true
    })
  }
}
</script>

 в form.targetStashLocationDev должен быть в селекторе по умолчанию выбран disk из formatedDisks