<script setup>
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import PkgCategoryTree from './components/PkgCategoryTree.vue'
import PkgList from './components/PkgList.vue'
import PkgDetail from './components/PkgDetail.vue'
import AddPackage from './components/AddPackage.vue'

// ── view state ────────────────────────────────────────────────────────────────
const currentView = ref('list') // 'list' | 'add'
const selectedCategoryId = ref('all')
const selectedPackage = ref(null)
const refreshKey = ref(0)

const handleCategorySelect = (categoryId) => {
  selectedCategoryId.value = categoryId
  selectedPackage.value = null
}

const handleViewPackage = (pkg) => {
  selectedPackage.value = pkg
}

const handleAddPackage = () => {
  currentView.value = 'add'
}

const handlePackageSaved = () => {
  currentView.value = 'list'
  refreshKey.value++
  selectedPackage.value = null
}

const handleAddCancel = () => {
  currentView.value = 'list'
}

// ── drag-resize layout ────────────────────────────────────────────────────────
const layoutRef = ref(null)
const leftPaneWidth = ref(16)
const middlePaneWidth = ref(38)
const dragState = ref(null)
const pendingDragX = ref(null)
let dragFrameId = 0
const layoutStorageKey = 'pkg-management-layout-v1'

const MIN_LEFT = 12
const MAX_LEFT = 24
const MIN_MIDDLE = 30
const MAX_MIDDLE = 56
const MIN_RIGHT = 24

const rightPaneWidth = computed(() =>
  Number((100 - leftPaneWidth.value - middlePaneWidth.value).toFixed(2)),
)

const setPaneWidths = (nextLeft, nextMiddle, target = 'left') => {
  let left = Math.min(Math.max(nextLeft, MIN_LEFT), MAX_LEFT)
  let middle = Math.min(Math.max(nextMiddle, MIN_MIDDLE), MAX_MIDDLE)

  if (100 - left - middle < MIN_RIGHT) {
    if (target === 'left') {
      left = 100 - middle - MIN_RIGHT
      if (left < MIN_LEFT) {
        left = MIN_LEFT
        middle = 100 - left - MIN_RIGHT
      }
    } else {
      middle = 100 - left - MIN_RIGHT
      if (middle < MIN_MIDDLE) {
        middle = MIN_MIDDLE
        left = 100 - middle - MIN_RIGHT
      }
    }
  }

  leftPaneWidth.value = Number(left.toFixed(2))
  middlePaneWidth.value = Number(middle.toFixed(2))
}

const loadLayoutCache = () => {
  const raw = localStorage.getItem(layoutStorageKey)
  if (!raw) return
  try {
    const parsed = JSON.parse(raw)
    if (typeof parsed.left === 'number' && typeof parsed.middle === 'number') {
      setPaneWidths(parsed.left, parsed.middle, 'middle')
    }
  } catch {
    localStorage.removeItem(layoutStorageKey)
  }
}

const saveLayoutCache = () => {
  localStorage.setItem(
    layoutStorageKey,
    JSON.stringify({ left: leftPaneWidth.value, middle: middlePaneWidth.value }),
  )
}

const applyDragPosition = (clientX) => {
  if (!dragState.value) return
  const delta = ((clientX - dragState.value.startX) / dragState.value.layoutWidth) * 100
  if (dragState.value.target === 'left') {
    setPaneWidths(dragState.value.startLeft + delta, dragState.value.startMiddle, 'left')
  } else {
    setPaneWidths(dragState.value.startLeft, dragState.value.startMiddle + delta, 'middle')
  }
}

const flushDragging = () => {
  dragFrameId = 0
  if (pendingDragX.value === null) return
  applyDragPosition(pendingDragX.value)
}

const stopDragging = () => {
  window.removeEventListener('mousemove', handleDragging)
  window.removeEventListener('mouseup', stopDragging)
  window.removeEventListener('mouseleave', stopDragging)
  window.removeEventListener('blur', stopDragging)
  document.body.style.userSelect = ''
  document.body.style.cursor = ''
  if (dragFrameId) {
    cancelAnimationFrame(dragFrameId)
    dragFrameId = 0
  }
  pendingDragX.value = null
  if (dragState.value) saveLayoutCache()
  dragState.value = null
}

const handleDragging = (event) => {
  if (!dragState.value) return
  pendingDragX.value = event.clientX
  if (!dragFrameId) {
    dragFrameId = requestAnimationFrame(flushDragging)
  }
}

const startDragging = (target, event) => {
  if (window.innerWidth <= 980 || !layoutRef.value) return
  event.preventDefault()
  stopDragging()
  dragState.value = {
    target,
    startX: event.clientX,
    startLeft: leftPaneWidth.value,
    startMiddle: middlePaneWidth.value,
    layoutWidth: layoutRef.value.clientWidth,
  }
  document.body.style.userSelect = 'none'
  document.body.style.cursor = 'col-resize'
  window.addEventListener('mousemove', handleDragging)
  window.addEventListener('mouseup', stopDragging)
  window.addEventListener('mouseleave', stopDragging)
  window.addEventListener('blur', stopDragging)
}

onMounted(loadLayoutCache)
onBeforeUnmount(stopDragging)
</script>

<template>
  <section class="pkg-page" :class="{ dragging: !!dragState }">
    <!-- add package sub-page -->
    <AddPackage v-if="currentView === 'add'" @saved="handlePackageSaved" @cancel="handleAddCancel" />

    <!-- list view: three-pane layout -->
    <div v-else ref="layoutRef" class="pkg-layout">
      <PkgCategoryTree
        :model-value="selectedCategoryId"
        :style="{ width: `${leftPaneWidth}%` }"
        @update:model-value="(v) => (selectedCategoryId = v)"
        @select="handleCategorySelect"
      />

      <div class="pane-divider" @mousedown.prevent="(e) => startDragging('left', e)" />

      <PkgList
        :category-id="selectedCategoryId"
        :refresh-key="refreshKey"
        :style="{ width: `${middlePaneWidth}%` }"
        @view="handleViewPackage"
        @add="handleAddPackage"
      />

      <div class="pane-divider" @mousedown.prevent="(e) => startDragging('middle', e)" />

      <PkgDetail
        :package="selectedPackage"
        :style="{ width: `${rightPaneWidth}%` }"
      />
    </div>
  </section>
</template>

<style lang="scss" scoped>
.pkg-page {
  height: 100%;
  background: var(--bg-page);

  &.dragging {
    user-select: none;
    cursor: col-resize;
  }
}

.pkg-layout {
  height: 100%;
  display: flex;
  align-items: stretch;
  gap: 0;
  background: var(--bg-white);
  border: 1px solid var(--border-color);
  box-shadow: var(--shadow-card);
}

.pane-divider {
  width: 4px;
  flex-shrink: 0;
  background: var(--border-color);
  cursor: col-resize;
  transition: background 0.15s;
  position: relative;

  &::after {
    content: '';
    position: absolute;
    inset: 0 -2px;
  }

  &:hover,
  .dragging & {
    background: var(--primary-border);
  }
}
</style>
