<script setup>
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
import DashboardLayout from '../layouts/DashboardLayout.vue'
import { Input } from '@/components/ui/input'

// ── Static graph data ──────────────────────────────────────
const TYPE_COLORS = {
  Customer:  '#6D28D9',
  Product:   '#DB2777',
  Category:  '#0891B2',
  Behavior:  '#EA580C',
  Segment:   '#B45309',
  Occasion:  '#065F46',
  Trend:     '#1D4ED8',
}

const GRAPH_DATA = {
  nodes: [
    { id:'c1', name:'N.T.Mai',      type:'Customer',  attrs:{ age:'32', segment:'VIP', city:'Hà Nội', ltv:'12.5M' } },
    { id:'c2', name:'T.V.Hùng',     type:'Customer',  attrs:{ age:'28', segment:'Regular', city:'TP.HCM', ltv:'4.2M' } },
    { id:'c3', name:'L.P.Anh',      type:'Customer',  attrs:{ age:'35', segment:'VIP', city:'Đà Nẵng', ltv:'18.7M' } },
    { id:'c4', name:'P.M.Tuấn',     type:'Customer',  attrs:{ age:'41', segment:'Premium', city:'Hà Nội', ltv:'9.8M' } },
    { id:'c5', name:'H.T.Linh',     type:'Customer',  attrs:{ age:'26', segment:'New', city:'TP.HCM', ltv:'1.5M' } },
    { id:'p1', name:'Polo Classic', type:'Product',   attrs:{ sku:'8TS26C005', price:'399K', stock:'245' } },
    { id:'p2', name:'Váy Midi',     type:'Product',   attrs:{ sku:'6VD24A012', price:'599K', stock:'120' } },
    { id:'p3', name:'Jeans Slim',   type:'Product',   attrs:{ sku:'7QJ25B003', price:'499K', stock:'180' } },
    { id:'p4', name:'Áo Bomber',    type:'Product',   attrs:{ sku:'8AK26D008', price:'799K', stock:'95' } },
    { id:'p5', name:'Đầm Công Sở',  type:'Product',   attrs:{ sku:'6DC24E015', price:'699K', stock:'75' } },
    { id:'p6', name:'Sơ Mi Linen',  type:'Product',   attrs:{ sku:'8SM26F002', price:'459K', stock:'200' } },
    { id:'cat1', name:'Thời trang Nữ', type:'Category', attrs:{ products:'156', revenue:'2.3B' } },
    { id:'cat2', name:'Thời trang Nam', type:'Category', attrs:{ products:'98', revenue:'1.1B' } },
    { id:'b1', name:'Mua cuối tuần', type:'Behavior', attrs:{ freq:'Weekly', channel:'Online+Offline' } },
    { id:'b2', name:'Flash Sale',   type:'Behavior',  attrs:{ freq:'Every sale', channel:'App' } },
    { id:'b5', name:'Loyal Repeat', type:'Behavior',  attrs:{ freq:'Monthly', channel:'All' } },
    { id:'s1', name:'Mom Shopper',  type:'Segment',   attrs:{ size:'2,340', growth:'+12%', avgLTV:'8.5M' } },
    { id:'s2', name:'Young Pro',    type:'Segment',   attrs:{ size:'1,850', growth:'+18%', avgLTV:'5.2M' } },
    { id:'s3', name:'Fashion Enth', type:'Segment',   attrs:{ size:'980',   growth:'+25%', avgLTV:'15.3M' } },
    { id:'t1', name:'Minimalism',   type:'Trend',     attrs:{ strength:'Strong', since:'2025' } },
    { id:'t2', name:'Sustainable',  type:'Trend',     attrs:{ strength:'Growing', since:'2024' } },
    { id:'o1', name:'Đi làm',       type:'Occasion',  attrs:{ peak:'Mon-Fri' } },
    { id:'o2', name:'Đi chơi',      type:'Occasion',  attrs:{ peak:'Weekend' } },
  ],
  edges: [
    { s:'c1', t:'p1', label:'mua', w:3 }, { s:'c1', t:'p2', label:'mua', w:5 }, { s:'c1', t:'p5', label:'mua', w:2 },
    { s:'c2', t:'p1', label:'mua', w:2 }, { s:'c2', t:'p3', label:'mua', w:4 }, { s:'c3', t:'p2', label:'mua', w:6 },
    { s:'c3', t:'p5', label:'mua', w:4 }, { s:'c4', t:'p3', label:'mua', w:3 }, { s:'c4', t:'p6', label:'mua', w:5 },
    { s:'c5', t:'p1', label:'xem', w:1 }, { s:'c5', t:'p2', label:'thích', w:2 },
    { s:'p1', t:'cat2', label:'thuộc', w:1 }, { s:'p2', t:'cat1', label:'thuộc', w:1 },
    { s:'p3', t:'cat2', label:'thuộc', w:1 }, { s:'p5', t:'cat1', label:'thuộc', w:1 },
    { s:'cat1', t:'t1', label:'xu hướng', w:2 }, { s:'cat1', t:'t2', label:'xu hướng', w:1 },
    { s:'c1', t:'s1', label:'thuộc nhóm', w:2 }, { s:'c2', t:'s2', label:'thuộc nhóm', w:2 },
    { s:'c3', t:'s3', label:'thuộc nhóm', w:3 }, { s:'c1', t:'b1', label:'hành vi', w:2 },
    { s:'c1', t:'b5', label:'hành vi', w:3 }, { s:'c2', t:'b2', label:'hành vi', w:2 },
    { s:'p1', t:'o1', label:'phù hợp', w:1 }, { s:'p5', t:'o1', label:'phù hợp', w:3 },
    { s:'p2', t:'o2', label:'phù hợp', w:2 }, { s:'c1', t:'c3', label:'tương tự', w:2 },
    { s:'p1', t:'p6', label:'mua kèm', w:3 },
  ]
}

// ── State ──────────────────────────────────────────────────
const svgRef    = ref(null)
const selected  = ref(null)   // { node, type: 'node'|'edge' }
const searchQ   = ref('')
const zoom      = ref(1)
const panX      = ref(0), panY = ref(0)
const isDrag    = ref(false)
const dragStart = ref({ x: 0, y: 0, px: 0, py: 0 })
const positions = ref({})

const TYPE_COUNT = Object.keys(TYPE_COLORS).reduce((acc, k) => {
  acc[k] = GRAPH_DATA.nodes.filter(n => n.type === k).length; return acc
}, {})

// ── Simple force-layout (no D3 needed) ────────────────────
function initPositions() {
  const n = GRAPH_DATA.nodes.length
  const cx = 600, cy = 340, r = 260
  GRAPH_DATA.nodes.forEach((node, i) => {
    const angle = (i / n) * Math.PI * 2
    positions.value[node.id] = {
      x: cx + Math.cos(angle) * r * (0.7 + Math.random() * 0.6),
      y: cy + Math.sin(angle) * r * (0.7 + Math.random() * 0.6)
    }
  })
}

function nodePos(id) { return positions.value[id] || { x: 600, y: 340 } }

function edgeMidpoint(edge) {
  const s = nodePos(edge.s), t = nodePos(edge.t)
  return { x: (s.x + t.x) / 2, y: (s.y + t.y) / 2 }
}

// ── Interaction ────────────────────────────────────────────
const draggingNode = ref(null)
let lastNodeDrag = { x: 0, y: 0 }

function startNodeDrag(e, nodeId) {
  e.stopPropagation()
  draggingNode.value = nodeId
  lastNodeDrag = { x: e.clientX, y: e.clientY }
  window.addEventListener('mousemove', onNodeDrag)
  window.addEventListener('mouseup', stopNodeDrag)
}

function onNodeDrag(e) {
  if (!draggingNode.value) return
  const dx = (e.clientX - lastNodeDrag.x) / zoom.value
  const dy = (e.clientY - lastNodeDrag.y) / zoom.value
  lastNodeDrag = { x: e.clientX, y: e.clientY }
  const p = positions.value[draggingNode.value]
  if (p) { p.x += dx; p.y += dy }
}
function stopNodeDrag() {
  draggingNode.value = null
  window.removeEventListener('mousemove', onNodeDrag)
  window.removeEventListener('mouseup', stopNodeDrag)
}

function selectNode(node) {
  selected.value = { item: node, type: 'node' }
}

function connections(nodeId) {
  return GRAPH_DATA.edges
    .filter(e => e.s === nodeId || e.t === nodeId)
    .map(e => ({
      dir: e.s === nodeId ? '→' : '←',
      label: e.label,
      other: GRAPH_DATA.nodes.find(n => n.id === (e.s === nodeId ? e.t : e.s))
    }))
    .filter(c => c.other)
}

// ── Pan/Zoom canvas (svg background) ──────────────────────
function svgMouseDown(e) {
  if (e.target !== svgRef.value && !e.target.tagName?.match(/^(svg|rect)$/i)) return
  isDrag.value = true
  dragStart.value = { x: e.clientX, y: e.clientY, px: panX.value, py: panY.value }
}
function svgMouseMove(e) {
  if (!isDrag.value) return
  panX.value = dragStart.value.px + (e.clientX - dragStart.value.x)
  panY.value = dragStart.value.py + (e.clientY - dragStart.value.y)
}
function svgMouseUp() { isDrag.value = false }
function svgWheel(e) {
  e.preventDefault()
  const delta = e.deltaY > 0 ? -0.1 : 0.1
  zoom.value = Math.min(Math.max(zoom.value + delta, 0.1), 4)
}

// ── Search filter ──────────────────────────────────────────
function nodeOpacity(nodeId) {
  if (!searchQ.value) return 1
  const q = searchQ.value.toLowerCase()
  const n = GRAPH_DATA.nodes.find(x => x.id === nodeId)
  return (n && (n.name.toLowerCase().includes(q) || n.type.toLowerCase().includes(q))) ? 1 : 0.1
}

onMounted(() => {
  initPositions()
  window.addEventListener('mousemove', svgMouseMove)
  window.addEventListener('mouseup', svgMouseUp)
})
onUnmounted(() => {
  window.removeEventListener('mousemove', svgMouseMove)
  window.removeEventListener('mouseup', svgMouseUp)
})
</script>

<template>
  <DashboardLayout>
    <div class="flex h-[calc(100vh-56px)] overflow-hidden">

      <!-- Left: Legend + Search + Detail -->
      <div class="w-[240px] shrink-0 flex flex-col border-r border-gray-100 bg-white">
        <!-- Header -->
        <div class="px-4 py-3 border-b">
          <h2 class="text-sm font-bold text-gray-800">🕸️ Knowledge Graph</h2>
          <Input v-model="searchQ" placeholder="Tìm node..." class="mt-2 h-7 text-xs" />
        </div>

        <!-- Legend -->
        <div class="px-4 py-3 border-b">
          <p class="text-[10px] font-bold text-gray-400 uppercase mb-2">Entity Types</p>
          <div class="space-y-1">
            <div v-for="(color, type) in TYPE_COLORS" :key="type"
                 v-if="TYPE_COUNT[type]"
                 class="flex items-center gap-2 text-xs">
              <span class="w-2.5 h-2.5 rounded-full shrink-0" :style="{ background: color }"></span>
              <span class="text-gray-600 flex-1">{{ type }}</span>
              <span class="text-gray-400 text-[10px]">{{ TYPE_COUNT[type] }}</span>
            </div>
          </div>
        </div>

        <!-- Stats -->
        <div class="px-4 py-2 border-b flex gap-3 text-xs">
          <div><span class="font-bold text-gray-800">{{ GRAPH_DATA.nodes.length }}</span> <span class="text-gray-400">nodes</span></div>
          <div><span class="font-bold text-gray-800">{{ GRAPH_DATA.edges.length }}</span> <span class="text-gray-400">edges</span></div>
        </div>

        <!-- Detail Panel -->
        <div class="flex-1 overflow-y-auto px-4 py-3">
          <div v-if="!selected" class="text-xs text-gray-400 text-center mt-6">Nhấn vào node để xem chi tiết</div>
          <div v-else>
            <div class="flex items-center gap-2 mb-3">
              <span class="w-2.5 h-2.5 rounded-full" :style="{ background: TYPE_COLORS[selected.item.type] }"></span>
              <span class="text-[10px] font-bold text-gray-500 uppercase">{{ selected.item.type }}</span>
            </div>
            <p class="text-sm font-bold text-gray-800 mb-3">{{ selected.item.name }}</p>
            <div class="space-y-1 mb-4">
              <div v-for="(v, k) in selected.item.attrs" :key="k" class="flex gap-2 text-xs">
                <span class="text-gray-400 w-16 shrink-0">{{ k }}</span>
                <span class="text-gray-700 font-medium">{{ v }}</span>
              </div>
            </div>
            <div v-if="connections(selected.item.id).length" class="border-t border-gray-100 pt-3">
              <p class="text-[10px] font-bold text-gray-400 uppercase mb-2">Connections ({{ connections(selected.item.id).length }})</p>
              <div class="space-y-1.5">
                <div v-for="c in connections(selected.item.id)" :key="c.other.id + c.label"
                     class="flex items-center gap-1.5 text-xs">
                  <span :class="['text-[10px] font-mono', c.dir === '→' ? 'text-blue-500' : 'text-orange-500']">{{ c.dir }}</span>
                  <span class="text-gray-400 text-[9px]">{{ c.label }}</span>
                  <span class="w-2 h-2 rounded-full shrink-0" :style="{ background: TYPE_COLORS[c.other.type] }"></span>
                  <span class="text-gray-700 truncate">{{ c.other.name }}</span>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- Controls -->
        <div class="flex gap-1 px-3 py-2 border-t">
          <button @click="zoom = Math.max(zoom - 0.2, 0.1)" class="flex-1 text-xs border border-gray-200 rounded py-1 hover:bg-gray-50">-</button>
          <button @click="zoom = 1; panX = 0; panY = 0" class="flex-1 text-[10px] border border-gray-200 rounded py-1 hover:bg-gray-50">Fit</button>
          <button @click="zoom = Math.min(zoom + 0.2, 4)" class="flex-1 text-xs border border-gray-200 rounded py-1 hover:bg-gray-50">+</button>
        </div>
      </div>

      <!-- Right: SVG Graph Canvas -->
      <div class="flex-1 overflow-hidden bg-[#f8f7f5] relative"
           @wheel.prevent="svgWheel"
           @mousedown="svgMouseDown"
           style="cursor: grab">
        <svg ref="svgRef" width="100%" height="100%">
          <defs>
            <marker id="arrow" viewBox="0 -4 8 8" refX="22" refY="0" markerWidth="5" markerHeight="5" orient="auto">
              <path d="M0,-4L8,0L0,4" fill="#C4C0B8" />
            </marker>
          </defs>

          <g :transform="`translate(${panX}, ${panY}) scale(${zoom})`">
            <!-- Edges -->
            <g v-for="edge in GRAPH_DATA.edges" :key="edge.s + edge.t + edge.label">
              <line
                :x1="nodePos(edge.s).x" :y1="nodePos(edge.s).y"
                :x2="nodePos(edge.t).x" :y2="nodePos(edge.t).y"
                stroke="#E2E0D8"
                :stroke-width="Math.max(1, (edge.w || 1) * 0.6)"
                marker-end="url(#arrow)"
                :opacity="searchQ ? (nodeOpacity(edge.s) + nodeOpacity(edge.t) > 0.5 ? 0.8 : 0.05) : 0.7"
              />
              <text
                :x="edgeMidpoint(edge).x" :y="edgeMidpoint(edge).y"
                font-size="8" fill="#A89E96" text-anchor="middle" dominant-baseline="middle"
                style="pointer-events:none; font-family: system-ui">
                {{ edge.label }}
              </text>
            </g>

            <!-- Nodes -->
            <g v-for="node in GRAPH_DATA.nodes" :key="node.id"
               :transform="`translate(${nodePos(node.id).x}, ${nodePos(node.id).y})`"
               :opacity="nodeOpacity(node.id)"
               style="cursor: pointer"
               @mousedown.stop="startNodeDrag($event, node.id)"
               @click.stop="selectNode(node)">
              <!-- Outer ring -->
              <circle r="20" fill="none"
                      :stroke="TYPE_COLORS[node.type]"
                      stroke-width="1.5"
                      :stroke-opacity="selected?.item?.id === node.id ? 0.5 : 0.12"
                      :style="{ transition: 'stroke-opacity .2s' }" />
              <!-- Main circle -->
              <circle r="13"
                      :fill="TYPE_COLORS[node.type]"
                      stroke="white"
                      :stroke-width="selected?.item?.id === node.id ? 3 : 2"
                      :style="{ transition: 'stroke-width .2s' }" />
              <!-- Icon -->
              <text font-size="9" fill="white" text-anchor="middle" dominant-baseline="central"
                    style="pointer-events:none; font-family: system-ui">
                {{ node.type === 'Customer' ? '👤' : node.type === 'Product' ? '🛍' : node.type === 'Segment' ? '👥' : node.type === 'Trend' ? '📈' : '' }}
              </text>
              <!-- Label -->
              <text dy="28" font-size="10" fill="#78716C" text-anchor="middle"
                    style="pointer-events:none; font-family: system-ui; font-weight: 500">
                {{ node.name.length > 12 ? node.name.slice(0, 11) + '…' : node.name }}
              </text>
            </g>
          </g>
        </svg>
      </div>
    </div>
  </DashboardLayout>
</template>
