<template>
  <div
    ref="cardRef"
    class="floating-alarm-card"
    :class="[`lvl-${level}`, { dragging }]"
    :style="cardStyle"
    @mousedown.stop="onMouseDown"
  >
    <div class="fac-header">
      <span class="fac-dot" />
      <span class="fac-title">{{ alarm.carName }} #{{ alarm.carId }}</span>
      <span class="fac-time">{{ timeShort }}</span>
      <el-icon class="fac-close" @click.stop="onClose"><Close /></el-icon>
    </div>
    <div class="fac-body">
      <div class="fac-info">{{ alarm.info }}</div>
      <div class="fac-coord">
        <span v-if="hasCoord">坐标 ({{ alarm.x?.toFixed(0) }}, {{ alarm.y?.toFixed(0) }}) mm</span>
        <span v-else class="muted">无坐标</span>
      </div>
    </div>
    <div class="fac-actions">
      <el-button size="small" plain :disabled="!hasCoord" @click.stop="onLocate">定位</el-button>
      <el-button size="small" plain @click.stop="onAck">确认</el-button>
      <el-button size="small" plain @click.stop="onSnooze">稍后</el-button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, ref } from 'vue'
import { Close } from '@element-plus/icons-vue'
import type { AlarmEvent } from '@/composables/useMapEditStream'

const props = defineProps<{
  alarm: AlarmEvent
  /** 卡片初始位置（相对父容器的右下角 offset，单位 px）。 */
  initialOffset?: { right: number; bottom: number }
}>()

const emit = defineEmits<{
  (e: 'close'): void
  (e: 'ack'): void
  (e: 'snooze'): void
  (e: 'locate', a: AlarmEvent): void
}>()

const cardRef = ref<HTMLDivElement | null>(null)
const dragging = ref(false)
const pos = ref<{ left?: number; top?: number; right?: number; bottom?: number }>({
  right: props.initialOffset?.right ?? 24,
  bottom: props.initialOffset?.bottom ?? 24
})

const hasCoord = computed(() => typeof props.alarm.x === 'number' && Number.isFinite(props.alarm.x))

const level = computed<'info' | 'warn' | 'error' | 'critical'>(() => {
  const s = (props.alarm.info || '').toLowerCase()
  if (s.includes('critical') || s.includes('严重') || s.includes('紧急')) return 'critical'
  if (s.includes('error') || s.includes('故障')) return 'error'
  if (s.includes('warn') || s.includes('告警')) return 'warn'
  return 'info'
})

const timeShort = computed(() => {
  try {
    const d = new Date(props.alarm.timestamp)
    return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })
  } catch { return '' }
})

const cardStyle = computed(() => ({
  left: pos.value.left !== undefined ? `${pos.value.left}px` : undefined,
  top: pos.value.top !== undefined ? `${pos.value.top}px` : undefined,
  right: pos.value.right !== undefined ? `${pos.value.right}px` : undefined,
  bottom: pos.value.bottom !== undefined ? `${pos.value.bottom}px` : undefined
}))

let startX = 0, startY = 0, originLeft = 0, originTop = 0

function onMouseDown(ev: MouseEvent) {
  if (!cardRef.value) return
  const rect = cardRef.value.getBoundingClientRect()
  originLeft = rect.left
  originTop = rect.top
  startX = ev.clientX
  startY = ev.clientY
  dragging.value = true
  window.addEventListener('mousemove', onMouseMove)
  window.addEventListener('mouseup', onMouseUp)
}
function onMouseMove(ev: MouseEvent) {
  pos.value = {
    left: originLeft + (ev.clientX - startX),
    top: originTop + (ev.clientY - startY)
  }
}
function onMouseUp() {
  dragging.value = false
  window.removeEventListener('mousemove', onMouseMove)
  window.removeEventListener('mouseup', onMouseUp)
}

onBeforeUnmount(() => {
  window.removeEventListener('mousemove', onMouseMove)
  window.removeEventListener('mouseup', onMouseUp)
})

function onClose() { emit('close') }
function onAck() { emit('ack') }
function onSnooze() { emit('snooze') }
function onLocate() { emit('locate', props.alarm) }
</script>

<style scoped>
.floating-alarm-card {
  position: absolute;
  width: 320px;
  padding: 10px 12px;
  border-radius: 10px;
  background: rgba(20, 8, 40, 0.92);
  backdrop-filter: blur(10px);
  box-shadow: 0 10px 32px rgba(10,2,16,0.55), 0 0 0 1px rgba(255,255,255,0.08) inset;
  color: rgba(232,215,245,0.95);
  font-size: 13px;
  cursor: grab;
  user-select: none;
  z-index: 1000;
  transition: box-shadow .2s, transform .2s;
}
.floating-alarm-card.dragging { cursor: grabbing; box-shadow: 0 14px 40px rgba(10,2,16,0.7); }
.fac-header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.fac-dot { width: 10px; height: 10px; border-radius: 999px; background: var(--lvl-color, #67c23a); box-shadow: 0 0 8px var(--lvl-color, #67c23a); }
.fac-title { flex: 1; font-weight: 600; }
.fac-time { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11.5px; color: rgba(232,215,245,0.65); }
.fac-close { cursor: pointer; opacity: .7; }
.fac-close:hover { opacity: 1; }
.fac-body { padding: 4px 0 6px; }
.fac-info { line-height: 1.4; word-break: break-all; }
.fac-coord { font-size: 11.5px; color: rgba(232,215,245,0.7); margin-top: 4px; font-family: ui-monospace, Menlo, Consolas, monospace; }
.fac-actions { display: flex; gap: 6px; justify-content: flex-end; }
.muted { color: rgba(232,215,245,0.5); }

.floating-alarm-card.lvl-info     { --lvl-color: #67c23a; }
.floating-alarm-card.lvl-warn     { --lvl-color: #e6a23c; }
.floating-alarm-card.lvl-error    { --lvl-color: #f56c6c; }
.floating-alarm-card.lvl-critical { --lvl-color: #d63a3a; }
</style>
