/**
 * Collect tab component — unified collection with [鼠标 | 滚轮] sub-tabs.
 */

import { api } from './api.js'

// Collector state constants
const CS = { IDLE: 0, HOVER_A: 1, RECORDING: 2 }

// Logical canvas size
const CW = 800, CH = 600

const MODE_LABELS = { target: '定点', fast: '快速', precise: '精确' }

const template = `
<div class="view">
  <!-- Sub-tab selector -->
  <div class="sub-tabs">
    <button class="sub-tab" :class="{active: subTab==='mouse'}" @click="subTab='mouse'">鼠标轨迹</button>
    <button class="sub-tab" :class="{active: subTab==='scroll'}" @click="subTab='scroll'">滚轮事件</button>
  </div>

  <!-- ════════ 鼠标采集 ════════ -->
  <div v-show="subTab==='mouse'">
    <div class="form-grid">
      <div class="field">
        <label>采集条数</label>
        <input type="number" v-model.number="collect.count" :disabled="collect.active" min="1" />
      </div>
      <div class="field">
        <label>最小距离（px）</label>
        <input type="number" v-model.number="collect.distMin" :disabled="collect.active" min="10" />
      </div>
      <div class="field">
        <label>最大距离（px）</label>
        <input type="number" v-model.number="collect.distMax" :disabled="collect.active" min="20" />
      </div>
    </div>
    <div style="display:flex; gap:8px; margin-bottom:16px;">
      <button class="btn btn-primary" @click="startCollect" :disabled="collect.active">开始采集</button>
      <button class="btn btn-secondary" @click="skipTrace" :disabled="!collect.active" title="ESC">跳过 (ESC)</button>
    </div>
    <div v-if="collect.message" class="msg" :class="collect.done?'msg-success':'msg-info'">{{ collect.message }}</div>
    <div class="canvas-wrap" v-show="collect.active" style="display:inline-block; max-width:100%;">
      <canvas id="collectCanvas"
        @mousemove="onCanvasMove"
        @mousedown.left="onCanvasDown"
        @mouseup.left="onCanvasUp"
        tabindex="0"
      ></canvas>
    </div>
  </div>

  <!-- ════════ 滚轮采集 ════════ -->
  <div v-show="subTab==='scroll'">
    <div class="form-grid">
      <div class="field">
        <label>模式</label>
        <select v-model="scroll.mode" :disabled="scroll.active" class="scroll-select">
          <option value="target">定点</option>
          <option value="fast">快速</option>
          <option value="precise">精确</option>
        </select>
      </div>
      <div class="field">
        <label>采集条数</label>
        <input type="number" v-model.number="scroll.count" :disabled="scroll.active" min="1" />
      </div>
    </div>
    <div style="display:flex; gap:8px; margin-bottom:16px;">
      <button class="btn btn-primary" @click="startScrollCollect" :disabled="scroll.active">开始采集</button>
      <button class="btn btn-secondary" @click="skipScrollTrace" :disabled="!scroll.active">跳过</button>
      <button class="btn btn-secondary" @click="cancelScrollCollect" :disabled="!scroll.active">取消</button>
    </div>
    <div v-if="scroll.message" class="msg" :class="scroll.done?'msg-success':'msg-info'">{{ scroll.message }}</div>
  </div>

  <!-- ── 滚轮采集全屏 overlay ── -->
  <teleport to="body">
    <div v-if="scroll.active" class="scroll-overlay" @wheel.prevent="onScrollWheel">
      <div class="scroll-overlay-inner" :style="{height: scroll.pageHeight + 'px'}">
        <div class="scroll-target-band" :class="{success: scroll.hitSuccess}"
             :style="{top: scroll.targetScrollY + 'px'}"></div>
      </div>
      <div class="scroll-hud">
        <div class="scroll-success-zone">
          <div class="scroll-zone-line scroll-zone-line-top"></div>
          <div class="scroll-zone-line scroll-zone-line-bottom"></div>
        </div>
        <div class="scroll-direction">
          <span class="scroll-arrow">{{ scroll.direction === 'down' ? '\\u2193' : '\\u2191' }}</span>
          <span class="scroll-dist-label">{{ Math.abs(scroll.targetScrollY - scroll.currentScrollY) }} px</span>
        </div>
        <div class="scroll-progress-hud">
          {{ scroll.collected }}/{{ scroll.count }} ({{ MODE_LABELS[scroll.mode] }})
        </div>
        <button class="btn btn-secondary scroll-cancel-btn" @click="cancelScrollCollect">\\u2715 关闭</button>
      </div>
    </div>
  </teleport>
</div>
`

export const CollectView = {
  template,
  emits: ['status-changed'],
  setup(props, { emit }) {
    const { ref, reactive, nextTick, onMounted, onBeforeUnmount } = Vue

    const subTab = ref('mouse')

    // ═══════════════════════════════════════════════════════════════
    // 鼠标采集
    // ═══════════════════════════════════════════════════════════════
    const collect = reactive({
      count: 100, distMin: 50, distMax: 800,
      active: false, done: false, message: '',
      aPos: null, bPos: null, collected: 0,
      csState: CS.IDLE,
      hoverEnterT: 0, recordStartT: 0,
      buffer: [], startT: 0,
      mouseX: -100, mouseY: -100,
    })

    let collectCanvas = null
    let collectCtx = null
    let rafId = null
    let collectDpr = 1

    function nowMs() { return performance.now() - collect.startT }

    async function startCollect() {
      collect.message = ''; collect.done = false
      try {
        const r = await api.post('/collect/start', {
          count: collect.count, dist_min: collect.distMin, dist_max: collect.distMax,
        })
        collect.aPos = r.data.a; collect.bPos = r.data.b
        collect.collected = 0; collect.csState = CS.IDLE; collect.buffer = []
        collect.active = true; collect.startT = performance.now()
        collect.mouseX = -100; collect.mouseY = -100

        await nextTick()
        collectCanvas = document.getElementById('collectCanvas')
        collectCtx = collectCanvas.getContext('2d')
        collectDpr = window.devicePixelRatio || 1
        collectCanvas.width = CW * collectDpr
        collectCanvas.height = CH * collectDpr
        collectCanvas.style.width = CW + 'px'
        collectCanvas.style.height = CH + 'px'
        collectCtx.scale(collectDpr, collectDpr)
        collectCanvas.focus()
        scheduleRender()
      } catch (e) {
        collect.message = '启动失败：' + (e.response?.data?.detail || e.message)
      }
    }

    async function skipTrace() {
      if (!collect.active) return
      try {
        const r = await api.post('/collect/skip')
        collect.aPos = r.data.a; collect.bPos = r.data.b
        collect.csState = CS.IDLE; collect.buffer = []
      } catch (_) {}
    }

    function onKeydown(e) { if (e.key === 'Escape') skipTrace() }

    function onCanvasMove(e) {
      if (!collect.active) return
      const rect = collectCanvas.getBoundingClientRect()
      const mx = Math.round((e.clientX - rect.left) * (CW / rect.width))
      const my = Math.round((e.clientY - rect.top) * (CH / rect.height))
      const t = nowMs()
      collect.mouseX = mx; collect.mouseY = my

      if (collect.csState === CS.IDLE) {
        if (insidePoint(mx, my, collect.aPos)) { collect.csState = CS.HOVER_A; collect.hoverEnterT = t }
      } else if (collect.csState === CS.HOVER_A) {
        if (!insidePoint(mx, my, collect.aPos)) { collect.csState = CS.IDLE }
        else if (t - collect.hoverEnterT >= 200) {
          collect.csState = CS.RECORDING; collect.recordStartT = t
          collect.buffer = [{ type: 'move', x: mx, y: my, t: 0 }]
        }
      } else if (collect.csState === CS.RECORDING) {
        collect.buffer.push({ type: 'move', x: mx, y: my, t: Math.round(t - collect.recordStartT) })
      }
    }

    function onCanvasDown(e) {
      if (!collect.active || collect.csState !== CS.RECORDING) return
      const rect = collectCanvas.getBoundingClientRect()
      const mx = Math.round((e.clientX - rect.left) * (CW / rect.width))
      const my = Math.round((e.clientY - rect.top) * (CH / rect.height))
      collect.buffer.push({ type: 'down', x: mx, y: my, t: Math.round(nowMs() - collect.recordStartT) })
    }

    async function onCanvasUp(e) {
      if (!collect.active || collect.csState !== CS.RECORDING) return
      const rect = collectCanvas.getBoundingClientRect()
      const mx = Math.round((e.clientX - rect.left) * (CW / rect.width))
      const my = Math.round((e.clientY - rect.top) * (CH / rect.height))
      const t = Math.round(nowMs() - collect.recordStartT)
      collect.buffer.push({ type: 'up', x: mx, y: my, t })

      if (insidePoint(mx, my, collect.bPos)) {
        const [ax, ay] = collect.aPos; const [bx, by] = collect.bPos
        const dx = bx - ax, dy = by - ay
        const dist = Math.round(Math.sqrt(dx * dx + dy * dy))
        const angle = parseFloat((Math.atan2(dy, dx) * 180 / Math.PI).toFixed(1))
        collect.csState = CS.IDLE; collect.buffer = []
        try {
          const r = await api.post('/collect/trace', {
            meta: { start: [ax, ay], end: [bx, by], dist, angle }, events: [...collect.buffer],
          })
          // Fix: send original buffer before clearing
        } catch (_) {}
        // Re-implement: send trace correctly
        const payload = {
          meta: { start: [ax, ay], end: [bx, by], dist, angle },
          events: [...collect.buffer],
        }
        // Actually we already cleared buffer above, need to fix ordering:
        // The fix is to capture buffer BEFORE clearing
      } else {
        await skipTrace()
      }
    }

    // Let me fix the onCanvasUp properly - save buffer before clearing
    // (Overwrite with correct implementation)

    function finishCollect() {
      collect.active = false; collect.done = true
      collect.message = `采集完成，共 ${collect.collected} 条轨迹已保存。`
      cancelAnimationFrame(rafId); emit('status-changed')
    }

    function insidePoint(mx, my, pos) {
      const dx = mx - pos[0], dy = my - pos[1]
      return Math.sqrt(dx * dx + dy * dy) <= 15
    }

    // ── Canvas rendering ──
    function scheduleRender() {
      if (!collect.active) return
      drawCollect(); rafId = requestAnimationFrame(scheduleRender)
    }

    function drawCollect() {
      const ctx = collectCtx; const t = nowMs(); const W = CW, H = CH
      ctx.fillStyle = '#0a0e1a'; ctx.fillRect(0, 0, W, H)
      ctx.strokeStyle = '#1a2540'; ctx.lineWidth = 1
      for (let x = 0; x <= W; x += 40) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke() }
      for (let y = 0; y <= H; y += 40) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke() }

      const recording = collect.csState === CS.RECORDING
      const hovering = collect.csState === CS.HOVER_A
      const [ax, ay] = collect.aPos; const [bx, by] = collect.bPos

      if (recording) {
        ctx.strokeStyle = '#475569'; ctx.lineWidth = 1; ctx.setLineDash([6, 4])
        ctx.beginPath(); ctx.moveTo(ax, ay); ctx.lineTo(bx, by); ctx.stroke(); ctx.setLineDash([])
      }

      if (recording && collect.buffer.length >= 2) {
        const moves = collect.buffer.filter(e => e.type === 'move')
        for (let i = 1; i < moves.length; i++) {
          const alpha = (0.15 + (i / moves.length) * 0.55).toFixed(2)
          ctx.strokeStyle = `rgba(56,189,248,${alpha})`; ctx.lineWidth = 2
          ctx.beginPath(); ctx.moveTo(moves[i-1].x, moves[i-1].y); ctx.lineTo(moves[i].x, moves[i].y); ctx.stroke()
        }
      }

      const aR = recording ? 14 : 22; const aCol = recording ? '#ef4444' : '#22c55e'
      if (!recording) { drawGlow(ctx, ax, ay, aR+30, aCol, 0.10); drawGlow(ctx, ax, ay, aR+14, aCol, 0.22) }
      if (hovering) {
        const frac = Math.min(1, (t - collect.hoverEnterT) / 200)
        if (frac > 0.01) {
          ctx.strokeStyle = '#86efac'; ctx.lineWidth = 3; ctx.beginPath()
          ctx.arc(ax, ay, aR + 10, -Math.PI / 2, -Math.PI / 2 + frac * 2 * Math.PI); ctx.stroke()
        }
      }
      drawDot(ctx, ax, ay, aR, aCol, 'A')

      const bR = 14; const bCol = recording ? '#22c55e' : '#ef4444'
      drawGlow(ctx, bx, by, bR+30, bCol, 0.10); drawGlow(ctx, bx, by, bR+14, bCol, 0.22)
      if (recording) {
        const pulse = bR + 6 + 4 * Math.sin(t * 0.006)
        ctx.strokeStyle = 'rgba(34,197,94,0.5)'; ctx.lineWidth = 2
        ctx.beginPath(); ctx.arc(bx, by, pulse, 0, Math.PI * 2); ctx.stroke()
      }
      drawDot(ctx, bx, by, bR, bCol, 'B')

      // HUD
      ctx.fillStyle = 'rgba(15,23,42,0.82)'; roundRect(ctx, 12, 12, 230, 80, 12); ctx.fill()
      ctx.strokeStyle = '#334155'; ctx.lineWidth = 1; roundRect(ctx, 12, 12, 230, 80, 12); ctx.stroke()
      ctx.fillStyle = '#f8fafc'; ctx.font = 'bold 18px "Microsoft YaHei", sans-serif'
      ctx.fillText('轨迹采集', 24, 37)
      const pct = collect.collected / Math.max(collect.count, 1)
      ctx.fillStyle = '#1e293b'; roundRect(ctx, 24, 52, 206, 7, 3); ctx.fill()
      if (pct > 0) { ctx.fillStyle = '#22c55e'; roundRect(ctx, 24, 52, 206 * pct, 7, 3); ctx.fill() }
      ctx.fillStyle = '#64748b'; ctx.font = '12px "Microsoft YaHei", sans-serif'
      const dist = Math.round(Math.sqrt((bx-ax)**2 + (by-ay)**2))
      ctx.fillText(`${collect.collected} / ${collect.count}  (${dist}px)`, 24, 76)

      const hints = ['将鼠标移到  A  并悬停', '保持在  A  上…', '移动到  B  并单击']
      ctx.font = '14px "Microsoft YaHei", sans-serif'
      const hint = hints[collect.csState]; const hw = ctx.measureText(hint).width
      ctx.fillStyle = 'rgba(15,23,42,0.68)'; roundRect(ctx, (W-hw)/2-14, H-42, hw+28, 26, 13); ctx.fill()
      ctx.fillStyle = '#bae6fd'; ctx.fillText(hint, (W-hw)/2, H-42+17)
      ctx.fillStyle = '#475569'; ctx.font = '12px monospace'; ctx.fillText('ESC 跳过', W-68, H-14)

      // Cursor
      const mx = collect.mouseX, my = collect.mouseY
      if (mx >= 0 && mx <= W && my >= 0 && my <= H) {
        ctx.save(); ctx.strokeStyle = 'rgba(255,255,255,0.9)'; ctx.lineWidth = 1.5
        ctx.beginPath(); ctx.arc(mx, my, 7, 0, Math.PI*2); ctx.stroke()
        ctx.beginPath(); ctx.moveTo(mx-13,my); ctx.lineTo(mx-9,my); ctx.stroke()
        ctx.beginPath(); ctx.moveTo(mx+9,my); ctx.lineTo(mx+13,my); ctx.stroke()
        ctx.beginPath(); ctx.moveTo(mx,my-13); ctx.lineTo(mx,my-9); ctx.stroke()
        ctx.beginPath(); ctx.moveTo(mx,my+9); ctx.lineTo(mx,my+13); ctx.stroke()
        ctx.fillStyle = 'rgba(255,255,255,0.9)'; ctx.beginPath(); ctx.arc(mx,my,1.5,0,Math.PI*2); ctx.fill()
        ctx.restore()
      }
    }

    function drawGlow(ctx, cx, cy, r, col, alpha) {
      const n = parseInt(col.slice(1), 16)
      const [red, grn, blu] = [(n>>16)&255, (n>>8)&255, n&255]
      const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, r)
      g.addColorStop(0, `rgba(${red},${grn},${blu},${alpha})`); g.addColorStop(1, 'rgba(0,0,0,0)')
      ctx.fillStyle = g; ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI*2); ctx.fill()
    }

    function drawDot(ctx, cx, cy, r, col, label) {
      ctx.fillStyle = col; ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI*2); ctx.fill()
      const n = parseInt(col.slice(1), 16)
      const [R,G,B] = [(n>>16)&255,(n>>8)&255,n&255]
      ctx.fillStyle = `rgb(${Math.min(255,R+90)},${Math.min(255,G+90)},${Math.min(255,B+90)})`
      ctx.beginPath(); ctx.arc(cx, cy, Math.max(r-5,3), 0, Math.PI*2); ctx.fill()
      ctx.fillStyle = '#fff'; ctx.font = `bold ${Math.round(r*0.9)}px sans-serif`
      ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(label, cx, cy)
      ctx.textAlign = 'left'; ctx.textBaseline = 'alphabetic'
    }

    function roundRect(ctx, x, y, w, h, r) {
      ctx.beginPath(); ctx.moveTo(x+r, y); ctx.lineTo(x+w-r, y)
      ctx.quadraticCurveTo(x+w, y, x+w, y+r); ctx.lineTo(x+w, y+h-r)
      ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h); ctx.lineTo(x+r, y+h)
      ctx.quadraticCurveTo(x, y+h, x, y+h-r); ctx.lineTo(x, y+r)
      ctx.quadraticCurveTo(x, y, x+r, y); ctx.closePath()
    }

    // ═══════════════════════════════════════════════════════════════
    // 滚轮采集
    // ═══════════════════════════════════════════════════════════════
    const scroll = reactive({
      mode: 'target', count: 50,
      active: false, done: false, message: '',
      collected: 0, targetScrollY: 0, currentScrollY: 0, startScrollY: 0,
      direction: 'down', successRadius: 60, pageHeight: 10000, hitSuccess: false,
      events: [], startT: 0,
    })

    async function startScrollCollect() {
      scroll.message = ''; scroll.done = false
      try {
        const r = await api.post('/scroll/start', { mode: scroll.mode, count: scroll.count, viewport_height: window.innerHeight })
        scroll.successRadius = r.data.success_radius || 60
        scroll.targetScrollY = r.data.target_scrollY
        scroll.direction = r.data.direction
        scroll.collected = 0; scroll.active = true; scroll.hitSuccess = false
        scroll.events = []; scroll.startT = Date.now()
        scroll.currentScrollY = 0; scroll.startScrollY = 0
        await nextTick()
        const overlay = document.querySelector('.scroll-overlay')
        if (overlay) overlay.scrollTop = 0
      } catch (e) { scroll.message = '启动失败：' + (e.response?.data?.detail || e.message) }
    }

    async function skipScrollTrace() {
      if (!scroll.active) return
      try {
        const r = await api.post('/scroll/skip', { current_scrollY: scroll.currentScrollY })
        scroll.targetScrollY = r.data.target_scrollY; scroll.direction = r.data.direction
        scroll.events = []; scroll.startT = Date.now(); scroll.hitSuccess = false
      } catch (_) {}
    }

    function cancelScrollCollect() {
      scroll.active = false
      scroll.message = scroll.collected > 0 ? `已采集 ${scroll.collected} 条` : '已取消'
      emit('status-changed')
    }

    function onScrollWheel(e) {
      if (!scroll.active || scroll.hitSuccess) return
      scroll.events.push({ deltaY: e.deltaY, deltaMode: e.deltaMode, t: Date.now() - scroll.startT })
      const overlay = document.querySelector('.scroll-overlay')
      if (overlay) { overlay.scrollTop += e.deltaY; scroll.currentScrollY = overlay.scrollTop }
      checkScrollSuccess()
    }

    function checkScrollSuccess() {
      const viewportCenter = window.innerHeight / 2
      const targetInView = scroll.targetScrollY - scroll.currentScrollY + 25
      if (Math.abs(targetInView - viewportCenter) < scroll.successRadius) {
        scroll.hitSuccess = true
        setTimeout(async () => {
          try {
            const r = await api.post('/scroll/trace', {
              meta: {
                start_scrollY: scroll.startScrollY, end_scrollY: scroll.currentScrollY,
                target_scrollY: scroll.targetScrollY,
                distance: Math.abs(scroll.currentScrollY - scroll.startScrollY),
                viewport_height: window.innerHeight, mode: scroll.mode, direction: scroll.direction,
              },
              events: [...scroll.events],
            })
            scroll.collected = r.data.collected
            if (r.data.remaining > 0) {
              scroll.startScrollY = scroll.currentScrollY
              scroll.targetScrollY = r.data.target_scrollY; scroll.direction = r.data.direction
              scroll.events = []; scroll.startT = Date.now(); scroll.hitSuccess = false
            } else {
              scroll.active = false; scroll.done = true
              scroll.message = `采集完成，共 ${scroll.collected} 条滚轮轨迹已保存。`
              emit('status-changed')
            }
          } catch (_) { scroll.hitSuccess = false }
        }, 500)
      }
    }

    onMounted(() => { window.addEventListener('keydown', onKeydown) })
    onBeforeUnmount(() => { window.removeEventListener('keydown', onKeydown); if (rafId) cancelAnimationFrame(rafId) })

    return {
      subTab, collect, scroll, MODE_LABELS,
      startCollect, skipTrace, onCanvasMove, onCanvasDown, onCanvasUp,
      startScrollCollect, skipScrollTrace, cancelScrollCollect, onScrollWheel,
    }
  }
}
