<template>
  <!-- ═══ 系统级审批提示浮窗(独立 WebviewWindow 内容)═══
       设计:
       - 无边框(decorations:false) + alwaysOnTop + skipTaskbar → 系统级可见
       - 紫色主题自定义样式(非 OS notification 默认)
       - 哑渲染器:监听主窗口推送的 approval-popup-update 事件,不重复监听 AI 事件
       - 操作按钮直调 aiApi.approve/authorizeDir(主窗口 listener 收后端 emit → 推新快照)
       - 点击「打开审批面板」emit approval-popup-activate → 主窗口聚焦 + togglePanel
       - 拖动条:.popup-drag(region CSS,WebviewWindow dataDrag 守卫)实现窗口拖动
       - 自动定位屏幕右上角(同 ApprovalOverlay 视觉一致) -->
  <div class="popup-shell" :data-dragging="isDragging">
    <!-- 顶部拖动条(双击不最大化,因 decorations:false) -->
    <div class="popup-header" data-tauri-drag-region @mousedown="onDragStart" @mouseup="onDragEnd">
      <div class="popup-header-icon">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M9 11l3 3L22 4" />
          <path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11" />
        </svg>
        <span v-if="approvals.length > 1" class="popup-header-badge">{{ approvals.length }}</span>
      </div>
      <div class="popup-header-title">{{ $t('aiChat.popupTitle') }}</div>
      <button class="popup-header-close" :title="$t('common.close')" @click.stop="onClose">
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <line x1="18" y1="6" x2="6" y2="18" />
          <line x1="6" y1="6" x2="18" y2="18" />
        </svg>
      </button>
    </div>

    <!-- 待审批列表 -->
    <div class="popup-body">
      <div v-if="approvals.length === 0" class="popup-empty">
        <!-- BUG2 修复:空态不再永久转圈(原 popup-empty-spinner 致「处理完仍转圈」误判卡死)。
             空态正常会被 maybeAutoClose 即时关窗;此 hint 仅作防御性兜底(close 失败时给可见反馈)。 -->
        <span class="popup-empty-hint">{{ $t('aiChat.popupEmptyHint') }}</span>
      </div>
      <div
        v-for="tc in approvals"
        :key="tc.id"
        class="popup-item"
        :class="'popup-item--' + (tc.kind || 'risk')"
      >
        <!-- 工具名 + kind 徽章 -->
        <div class="popup-item-header">
          <span class="popup-item-name">{{ displayName(tc) }}</span>
          <span v-if="tc.kind === 'path'" class="popup-item-tag popup-item-tag--path">
            {{ $t('aiChat.popupTagPath') }}
          </span>
          <span v-else class="popup-item-tag popup-item-tag--risk">
            {{ $t('aiChat.popupTagRisk') }}
          </span>
        </div>
        <!-- 风险说明(后端 build_approval_reason 已含工具/参数/risk 描述) -->
        <div v-if="tc.reason" class="popup-item-reason">⚠ {{ tc.reason }}</div>
        <!-- path 类:目录提示 -->
        <div v-if="tc.kind === 'path' && tc.dir" class="popup-item-dir">
          📁 {{ tc.dir }}
        </div>
        <!-- 操作按钮组 -->
        <div class="popup-item-actions">
          <button
            class="popup-btn popup-btn--approve"
            :disabled="processingId === tc.id"
            @click.stop="onApprove(tc)"
          >
            <span v-if="processingId === tc.id" class="popup-btn-spinner"></span>
            <svg v-else width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
            {{ tc.kind === 'path' ? $t('aiChat.dirAuthOnce') : $t('aiTool.approve') }}
          </button>
          <button
            class="popup-btn popup-btn--reject"
            :disabled="processingId === tc.id"
            @click.stop="onReject(tc)"
          >
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
            {{ $t('aiTool.reject') }}
          </button>
        </div>
      </div>
    </div>

    <!-- 底部:打开审批面板(聚焦主窗口) -->
    <button class="popup-footer" @click="onActivate">
      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M15 3h6v6" /><path d="M9 21H3v-6" /><path d="M21 3l-7 7" /><path d="M3 21l7-7" />
      </svg>
      {{ $t('aiChat.popupOpenPanel') }}
    </button>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { aiApi } from '@/api'
import { useToolCardHeader } from '@/composables/ai/useToolCardHeader'
import { ApprovalPopupEvents } from '@/composables/ai/useApprovalPopup'
import type { AiToolCallInfo } from '@/api/types'

/** 主窗口推送的快照(唯一真相源,本组件不监听 AI 事件) */
const approvals = ref<AiToolCallInfo[]>([])
/** 操作中 id(防抖 + 按钮加载态) */
const processingId = ref<string>('')
/** 拖动态(样式反馈) */
const isDragging = ref(false)

// 工具显示名复用 ToolCard 同款逻辑(语义化回显:写入/读取/$ cmd/GET host 等)。
// useToolCardHeader 的 getTc 入参仅供 displayArgValue/argsEntries 使用,toolDisplayName
// 直接接受 tc 参数(getTc 不被 toolDisplayName 调用),故传一个无副作用占位 getter 即可。
// 占位 getter 返回一个空 name 的对象,确保 displayArgValue 等即便误调也不会抛错。
const _placeholder = { name: '' } as AiToolCallInfo
const { toolDisplayName } = useToolCardHeader(() => _placeholder)
function displayName(tc: AiToolCallInfo): string {
  return toolDisplayName(tc)
}

let _unlistenUpdate: UnlistenFn | null = null
let _positioned = false

onMounted(async () => {
  // 首屏定位到屏幕右上角(只定位一次,后续保留用户拖动后位置)
  if (!_positioned) {
    _positioned = true
    try {
      const { currentMonitor } = await import('@tauri-apps/api/window')
      const { LogicalPosition } = await import('@tauri-apps/api/dpi')
      const mon = await currentMonitor()
      if (mon) {
        const win = getCurrentWebviewWindow()
        const w = 380
        // 逻辑坐标(mon.size 是物理像素,scaleFactor 转逻辑);仅用 X 定位右侧,Y 用固定顶部 16px
        const scale = mon.scaleFactor || 1
        const screenW = mon.size.width / scale
        const x = screenW - w - 16
        const y = 16 + (mon.position.y / scale)
        await win.setPosition(new LogicalPosition(x, y))
      }
    } catch { /* 定位失败不影响功能 */ }
  }

  // 监听主窗口推送的 pending 快照
  try {
    _unlistenUpdate = await listen<{ approvals: AiToolCallInfo[] }>(
      ApprovalPopupEvents.EVT_UPDATE,
      (e) => {
        approvals.value = e.payload?.approvals || []
        // BUG2 修复:主窗口推空快照(所有 pending 已清)→ 立即关浮窗,避免停留在空态转圈
        void maybeAutoClose()
      },
    )
  } catch (e) {
    console.error('[ApprovalPopup] 监听 update 事件失败:', e)
  }

  // 主动拉一次数据(主窗口可能在浮窗 listen 之前 emit,本次拉取兜底)
  try {
    const { emit } = await import('@tauri-apps/api/event')
    // 用 request-reply 太重,直接 emit 一个轻量事件让主窗口重推快照
    await emit('approval-popup-ready', {})
  } catch { /* ignore */ }
})

onBeforeUnmount(() => {
  _unlistenUpdate?.()
  _unlistenUpdate = null
})

/** 批准:risk 类 approve(true),path 类 authorizeDir('once') */
async function onApprove(tc: AiToolCallInfo) {
  if (processingId.value === tc.id) return
  processingId.value = tc.id
  try {
    if (tc.kind === 'path') {
      await aiApi.authorizeDir(tc.id, 'once')
    } else {
      await aiApi.approve(tc.id, true)
    }
    // 乐观移除(主窗口 listener 收后端 emit 后会推新快照覆盖,此乐观仅缩短视觉延迟)
    approvals.value = approvals.value.filter(a => a.id !== tc.id)
    // BUG2 修复:乐观移除后若列表空,立即关浮窗(避免空列表停留在 popup-empty 永久转圈态)
    await maybeAutoClose()
  } catch (e) {
    console.error('[ApprovalPopup] 批准失败:', e)
  } finally {
    processingId.value = ''
  }
}

/** 拒绝:risk 类 approve(false),path 类 authorizeDir('deny') */
async function onReject(tc: AiToolCallInfo) {
  if (processingId.value === tc.id) return
  processingId.value = tc.id
  try {
    if (tc.kind === 'path') {
      await aiApi.authorizeDir(tc.id, 'deny')
    } else {
      await aiApi.approve(tc.id, false)
    }
    approvals.value = approvals.value.filter(a => a.id !== tc.id)
    await maybeAutoClose()
  } catch (e) {
    console.error('[ApprovalPopup] 拒绝失败:', e)
  } finally {
    processingId.value = ''
  }
}

/** 列表清空时自动关浮窗。
 *  场景:用户处理完最后一条审批 / 主窗口推空快照(EVT_UPDATE approvals:[])。
 *  修复 BUG2:原实现空列表渲染 popup-empty + 永久 popup-empty-spinner,用户看到「列表空 + 一直转」
 *  误以为卡死。空 = 完成,应即时关浮窗(不等待主窗口 watch closePopup 的跨窗口往返)。 */
async function maybeAutoClose() {
  if (approvals.value.length > 0) return
  try {
    const { emit } = await import('@tauri-apps/api/event')
    // 先关窗(确保用户立刻看到反馈),再 emit 清主窗口引用(顺序与 onClose 一致)
    await getCurrentWebviewWindow().close()
    await emit(ApprovalPopupEvents.EVT_CLOSED, {})
  } catch { /* ignore */ }
}

/** 点击「打开审批面板」:emit 主窗口聚焦 + togglePanel */
async function onActivate() {
  try {
    const { emit } = await import('@tauri-apps/api/event')
    await emit(ApprovalPopupEvents.EVT_ACTIVATE, {})
  } catch { /* ignore */ }
}

/** 关闭浮窗(用户主动关 → emit closed 让主窗口清引用,允许下次有新审批再弹)
 *  修复 BUG3:原顺序 emit→close,若 emit 跨窗口分发阻塞/异常(close 永不执行)→ 关闭按钮「无效」。
 *  改为先 close(即时反馈,core:window:allow-close 已授权),再 emit 清主窗口引用;
 *  即便 emit 失败,主窗口 win.once('tauri://destroyed') 也会清 _popupWin(双保险)。 */
async function onClose() {
  try {
    await getCurrentWebviewWindow().close()
  } catch { /* ignore */ }
  try {
    const { emit } = await import('@tauri-apps/api/event')
    await emit(ApprovalPopupEvents.EVT_CLOSED, {})
  } catch { /* ignore */ }
}

// 拖动样式反馈(实际拖动由 data-tauri-drag-region + Tauri dataDrag 守卫处理)
function onDragStart() { isDragging.value = true }
function onDragEnd() { isDragging.value = false }
</script>

<style scoped>
/* 浮窗根:无边框 + 紫色主题阴影 */
.popup-shell {
  display: flex;
  flex-direction: column;
  width: 100vw;
  height: 100vh;
  background: var(--df-bg-card);
  border: 0.5px solid var(--df-accent);
  border-left: 3px solid var(--df-accent);
  border-radius: var(--df-radius-md);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(123, 111, 240, 0.2);
  overflow: hidden;
  user-select: none;
}
.popup-shell[data-dragging="true"] {
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6), 0 0 0 2px var(--df-accent);
}

/* 顶部拖动条 */
.popup-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: linear-gradient(135deg, var(--df-accent-bg), transparent);
  border-bottom: 0.5px solid var(--df-border, rgba(123, 111, 240, 0.2));
  cursor: move;
}
.popup-header-icon {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--df-accent-bg);
  color: var(--df-accent);
  flex-shrink: 0;
}
.popup-header-badge {
  position: absolute;
  top: -3px;
  right: -3px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--df-danger);
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  border: 1.5px solid var(--df-bg-card);
}
.popup-header-title {
  flex: 1;
  font-size: 12px;
  font-weight: 600;
  color: var(--df-text);
}
.popup-header-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: var(--df-radius-sm);
  background: transparent;
  color: var(--df-text-dim);
  cursor: pointer;
  flex-shrink: 0;
  transition: all 0.15s var(--df-ease);
}
.popup-header-close:hover {
  background: var(--df-sidebar-hover);
  color: var(--df-text);
}

/* 列表区(可滚动) */
.popup-body {
  flex: 1;
  overflow-y: auto;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.popup-empty {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-height: 80px;
  padding: 16px;
}
.popup-empty-hint {
  font-size: 11px;
  color: var(--df-text-dim);
  line-height: 1.4;
}

/* 单条审批项 */
.popup-item {
  padding: 8px 10px;
  border-radius: var(--df-radius-sm);
  background: var(--df-sidebar-hover);
  border-left: 2px solid var(--df-accent);
  transition: all 0.15s var(--df-ease);
}
.popup-item--path { border-left-color: var(--df-accent); }
.popup-item--risk { border-left-color: var(--df-warning, #f0a020); }
.popup-item:hover {
  background: var(--df-sidebar-active, rgba(123, 111, 240, 0.12));
}

.popup-item-header {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 4px;
}
.popup-item-name {
  flex: 1;
  font-size: 12px;
  font-weight: 600;
  color: var(--df-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.popup-item-tag {
  flex-shrink: 0;
  padding: 1px 6px;
  border-radius: 8px;
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.popup-item-tag--path {
  background: var(--df-accent-bg);
  color: var(--df-accent);
}
.popup-item-tag--risk {
  background: rgba(240, 160, 32, 0.18);
  color: var(--df-warning, #f0a020);
}

.popup-item-reason {
  font-size: 11px;
  color: var(--df-text-dim);
  line-height: 1.4;
  margin-bottom: 4px;
  word-break: break-word;
  white-space: normal;
}
.popup-item-dir {
  font-size: 10px;
  color: var(--df-text-dim);
  margin-bottom: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.popup-item-actions {
  display: flex;
  gap: 6px;
  margin-top: 6px;
}
.popup-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 5px 8px;
  border: none;
  border-radius: var(--df-radius-sm);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s var(--df-ease);
}
.popup-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.popup-btn--approve {
  background: var(--df-accent);
  color: #fff;
}
.popup-btn--approve:hover:not(:disabled) {
  background: var(--df-accent-hover, #6558d8);
}
.popup-btn--reject {
  background: var(--df-sidebar-hover);
  color: var(--df-text-dim);
  border: 0.5px solid var(--df-border, rgba(255, 255, 255, 0.1));
}
.popup-btn--reject:hover:not(:disabled) {
  background: rgba(255, 80, 80, 0.15);
  color: var(--df-danger, #e5484d);
}
.popup-btn-spinner {
  width: 10px;
  height: 10px;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: df-spin 0.6s linear infinite;
  display: inline-block;
}

/* 底部:打开审批面板 */
.popup-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px;
  border: none;
  border-top: 0.5px solid var(--df-border, rgba(123, 111, 240, 0.2));
  background: var(--df-accent-bg);
  color: var(--df-accent);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s var(--df-ease);
}
.popup-footer:hover {
  background: var(--df-accent);
  color: #fff;
}

@keyframes df-spin {
  to { transform: rotate(360deg); }
}
</style>
