<template>
  <div v-if="units.length" class="graphic-layout">
    <div class="unit-grid">
      <button
        v-for="unit in sortedUnits"
        :key="unit.unit_number"
        type="button"
        class="unit-tile"
        :class="[unit.status, { selected: selectedUnitNumbers.has(unit.unit_number) }]"
        :title="`U${unit.unit_number} · ${getTileText(unit)}`"
        @click="emit('select', unit)"
      >
        <strong>U{{ unit.unit_number }}</strong>
        <span>{{ getTileText(unit) }}</span>
      </button>
    </div>

    <aside class="unit-detail">
      <template v-if="selectedUnit">
        <h3>U 位详情</h3>
        <a-descriptions :column="1" size="small">
          <a-descriptions-item label="U 位范围">U{{ selectedStartUnit }} - U{{ selectedEndUnit }}</a-descriptions-item>
          <a-descriptions-item label="状态">{{ statusMeta[selectedUnit.status].text }}</a-descriptions-item>
          <template v-if="selectedUnit.status === 'occupied'">
            <a-descriptions-item label="设备名称">{{ selectedUnit.asset_name }}</a-descriptions-item>
            <a-descriptions-item label="设备编号">{{ selectedUnit.asset_code }}</a-descriptions-item>
            <a-descriptions-item label="设备类型">{{ selectedUnit.asset_type }}</a-descriptions-item>
            <a-descriptions-item label="功耗">{{ selectedUnit.power_consumption }}W</a-descriptions-item>
          </template>
          <template v-else-if="selectedUnit.status === 'reserved'">
            <a-descriptions-item label="预留对象">{{ selectedUnit.reserved_for }}</a-descriptions-item>
            <a-descriptions-item label="截止时间">{{ selectedUnit.reserved_until }}</a-descriptions-item>
          </template>
        </a-descriptions>

        <div class="detail-actions">
          <template v-if="selectedUnit.status === 'available'">
            <a-button type="primary" @click="emit('allocate', selectedUnit)">分配 U 位</a-button>
            <a-button @click="emit('reserve', selectedUnit)">预留 U 位</a-button>
            <a-button status="danger" @click="emit('disable', selectedUnit)">禁用</a-button>
          </template>
          <a-button v-else-if="selectedUnit.status === 'occupied'" status="danger" @click="emit('release', selectedUnit)">释放</a-button>
          <a-button v-else-if="selectedUnit.status === 'reserved'" status="danger" @click="handleCancelReservation">取消预留</a-button>
          <a-button v-else-if="selectedUnit.status === 'disabled'" @click="emit('enable', selectedUnit)">启用</a-button>
        </div>
      </template>
      <a-empty v-else description="请选择 U 位" />
    </aside>
  </div>
  <a-empty v-else description="请先选择机柜" />
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import type { RackUnitItem, RackUnitStatus } from '@/api/ops/unit'

interface Props {
  units: RackUnitItem[]
  selectedUnitNumber?: number
}

interface UnitRangeAction {
  unit: RackUnitItem
  startUnit: number
  endUnit: number
}

interface Emits {
  (event: 'select', unit: RackUnitItem): void
  (event: 'allocate', unit: RackUnitItem): void
  (event: 'reserve', unit: RackUnitItem): void
  (event: 'disable', unit: RackUnitItem): void
  (event: 'enable', unit: RackUnitItem): void
  (event: 'release', unit: RackUnitItem): void
  (event: 'cancel-reservation', payload: UnitRangeAction): void
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()

const statusMeta: Record<RackUnitStatus, { text: string; tileText: string }> = {
  available: { text: '可用', tileText: '可用' },
  occupied: { text: '已占用', tileText: '占用' },
  reserved: { text: '已预留', tileText: '预留' },
  disabled: { text: '已禁用', tileText: '禁用' },
}

const sortedUnits = computed(() => [...props.units].sort((left, right) => right.unit_number - left.unit_number))
const selectedUnit = computed(() => props.units.find((unit) => unit.unit_number === props.selectedUnitNumber))

const getTileText = (unit: RackUnitItem) => {
  if (unit.status === 'occupied') return unit.asset_code
  if (unit.status === 'reserved') return unit.reserved_for
  return statusMeta[unit.status].tileText
}

const isSameReservation = (left: RackUnitItem, right: RackUnitItem) => {
  return (
    left.status === 'reserved' &&
    right.status === 'reserved' &&
    left.reserved_for === right.reserved_for &&
    left.reserved_until === right.reserved_until
  )
}

const getReservedGroup = (unit: RackUnitItem) => {
  const unitMap = new Map(props.units.map((item) => [item.unit_number, item]))
  const result = [unit]

  for (const direction of [-1, 1]) {
    let unitNumber = unit.unit_number + direction
    let candidate = unitMap.get(unitNumber)
    while (candidate && isSameReservation(unit, candidate)) {
      result.push(candidate)
      unitNumber += direction
      candidate = unitMap.get(unitNumber)
    }
  }

  return result
}

const selectedGroup = computed(() => {
  const unit = selectedUnit.value
  if (!unit) return []
  if (unit.status === 'occupied') {
    return props.units.filter((item) => item.status === 'occupied' && item.asset_id === unit.asset_id)
  }
  if (unit.status === 'reserved') return getReservedGroup(unit)
  return [unit]
})

const selectedUnitNumbers = computed(() => new Set(selectedGroup.value.map((unit) => unit.unit_number)))
const selectedStartUnit = computed(() => Math.min(...selectedGroup.value.map((unit) => unit.unit_number)))
const selectedEndUnit = computed(() => Math.max(...selectedGroup.value.map((unit) => unit.unit_number)))

const handleCancelReservation = () => {
  const unit = selectedUnit.value
  if (!unit) return
  emit('cancel-reservation', {
    unit,
    startUnit: selectedStartUnit.value,
    endUnit: selectedEndUnit.value,
  })
}
</script>

<style scoped lang="less">
.graphic-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  min-height: 520px;
}

.unit-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(84px, 1fr));
  align-content: start;
  gap: 10px;
  padding: 20px;
}

.unit-tile {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
  height: 58px;
  padding: 9px 10px;
  border: 1px solid transparent;
  border-radius: 5px;
  text-align: left;
  cursor: pointer;

  span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.unit-tile.available {
  color: #006d22;
  border-color: #7be188;
  background: #e8ffea;
}

.unit-tile.occupied {
  color: #0e42d2;
  border-color: #94bfff;
  background: #e8f3ff;
}

.unit-tile.reserved {
  color: #b54708;
  border-color: #ffb65d;
  background: #fff7e8;
}

.unit-tile.disabled {
  color: #4e5969;
  border-color: #c9cdd4;
  background: repeating-linear-gradient(135deg, #f2f3f5 0, #f2f3f5 6px, #e5e6eb 6px, #e5e6eb 10px);
}

.unit-tile.selected {
  outline: 3px solid rgba(114, 46, 209, 0.72);
  outline-offset: 1px;
  box-shadow: 0 0 0 5px rgba(114, 46, 209, 0.11);
}

.unit-detail {
  padding: 20px;
  border-left: 1px solid #e5e6eb;

  h3 {
    margin: 0 0 16px;
  }
}

.detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 20px;
}
</style>
