<template>
  <div v-show="visible" class="fp-root" :style="rootStyle" @mousedown.stop>
    <div class="fp-header" @mousedown.prevent.stop="onDragStart">
      <div class="fp-title">{{ title }}</div>
      <div class="fp-actions">
        <el-button type="text" class="fp-btn" @click.stop="toggleMinimize">
          <i :class="minimized ? 'el-icon-caret-bottom' : 'el-icon-caret-top'"></i>
        </el-button>
        <el-button type="text" class="fp-btn" @click.stop="close">
          <i class="el-icon-close"></i>
        </el-button>
      </div>
    </div>

    <div v-show="!minimized" class="fp-body">
      <slot />
    </div>

    <!-- Resize handle / 缩放手柄 -->
    <div v-show="!minimized" class="fp-resize" @mousedown.prevent.stop="onResizeStart"></div>
  </div>
</template>

<script>
// English UI + Chinese comments
export default {
  name: 'FloatingPanel',
  props: {
    title: { type: String, default: 'Floating Panel' },
    storageKey: { type: String, required: true },
    defaultX: { type: Number, default: 20 },
    defaultY: { type: Number, default: 20 },
    defaultW: { type: Number, default: 420 },
    defaultH: { type: Number, default: 520 }
  },
  data() {
    return {
      visible: true,
      minimized: false,
      x: this.defaultX,
      y: this.defaultY,
      w: this.defaultW,
      h: this.defaultH,

      dragging: false,
      resizing: false,
      startMouseX: 0,
      startMouseY: 0,
      startX: 0,
      startY: 0,
      startW: 0,
      startH: 0
    }
  },
  computed: {
    rootStyle() {
      return {
        left: this.x + 'px',
        top: this.y + 'px',
        width: this.w + 'px',
        height: this.minimized ? 'auto' : this.h + 'px'
      }
    }
  },
  created() {
    this.restore()
  },
  beforeDestroy() {
    this.detachEvents()
  },
  methods: {
    // 外部可调用：重新打开
    open() {
      this.visible = true
      this.persist()
    },
    close() {
      this.visible = false
      this.persist()
      this.$emit('close')
    },
    toggleMinimize() {
      this.minimized = !this.minimized
      this.persist()
    },

    restore() {
      try {
        const raw = localStorage.getItem(this.storageKey)
        if (!raw) return
        const s = JSON.parse(raw)
        if (typeof s.visible === 'boolean') this.visible = s.visible
        if (typeof s.minimized === 'boolean') this.minimized = s.minimized
        if (typeof s.x === 'number') this.x = s.x
        if (typeof s.y === 'number') this.y = s.y
        if (typeof s.w === 'number') this.w = s.w
        if (typeof s.h === 'number') this.h = s.h
      } catch (e) {
        // ignore
      }
    },
    persist() {
      try {
        localStorage.setItem(
          this.storageKey,
          JSON.stringify({
            visible: this.visible,
            minimized: this.minimized,
            x: this.x,
            y: this.y,
            w: this.w,
            h: this.h
          })
        )
      } catch (e) {
        // ignore
      }
    },

    // Drag
    onDragStart(e) {
      this.dragging = true
      this.startMouseX = e.clientX
      this.startMouseY = e.clientY
      this.startX = this.x
      this.startY = this.y
      this.attachEvents()
    },
    onDragMove(e) {
      if (!this.dragging) return
      const dx = e.clientX - this.startMouseX
      const dy = e.clientY - this.startMouseY
      this.x = Math.max(0, this.startX + dx)
      this.y = Math.max(0, this.startY + dy)
    },
    onDragEnd() {
      if (!this.dragging) return
      this.dragging = false
      this.persist()
      this.detachEvents()
    },

    // Resize
    onResizeStart(e) {
      this.resizing = true
      this.startMouseX = e.clientX
      this.startMouseY = e.clientY
      this.startW = this.w
      this.startH = this.h
      this.attachEvents()
    },
    onResizeMove(e) {
      if (!this.resizing) return
      const dx = e.clientX - this.startMouseX
      const dy = e.clientY - this.startMouseY
      const minW = 320
      const minH = 220
      this.w = Math.max(minW, this.startW + dx)
      this.h = Math.max(minH, this.startH + dy)
    },
    onResizeEnd() {
      if (!this.resizing) return
      this.resizing = false
      this.persist()
      this.detachEvents()
    },

    attachEvents() {
      window.addEventListener('mousemove', this.onGlobalMove)
      window.addEventListener('mouseup', this.onGlobalUp)
    },
    detachEvents() {
      window.removeEventListener('mousemove', this.onGlobalMove)
      window.removeEventListener('mouseup', this.onGlobalUp)
    },
    onGlobalMove(e) {
      // 复用一套全局事件
      this.onDragMove(e)
      this.onResizeMove(e)
    },
    onGlobalUp() {
      this.onDragEnd()
      this.onResizeEnd()
    }
  }
}
</script>

<style scoped>
.fp-root {
  position: fixed;
  z-index: 9999;
  background: #ffffff;
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  overflow: hidden;
}
.fp-header {
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px;
  background: linear-gradient(135deg, #f5f7fa, #eef2f7);
  border-bottom: 1px solid #ebeef5;
  cursor: move;
  user-select: none;
}
.fp-title {
  font-size: 13px;
  font-weight: 600;
  color: #303133;
}
.fp-actions {
  display: flex;
  gap: 4px;
}
.fp-btn {
  padding: 0 4px;
}
.fp-body {
  height: calc(100% - 36px);
  padding: 10px;
  overflow: auto;
}
.fp-resize {
  position: absolute;
  width: 14px;
  height: 14px;
  right: 0;
  bottom: 0;
  cursor: se-resize;
  background: linear-gradient(135deg, transparent 50%, rgba(64, 158, 255, 0.35) 50%);
}
</style>

