<template>
  <div class="main">
    <el-scrollbar class="left"> <!-- 左边栏 -->
      <div class="center-line"> <!-- 左边栏按钮 -->
        <div v-for="(btn, index) in buttons" :key="index" style="width: 100%;">
          <div v-if="btn.show?.()" class="left-button" :style="btn.style ? btn.style() : {}" @click="btn.onClick"
            @mouseenter="hoverIndex = index" @mouseleave="hoverIndex = null">
            <img :src="hoverIndex === index ? btn.img.hover : btn.img.normal" alt="">
            {{ btn.label }}
          </div>
        </div>
        <div style="position: absolute;left: 20px; bottom: 20px;">
          <el-button @click="showHostDlg = true">执行主播库</el-button>
          <el-button type="info" @click="uploadLogFile">上传日志</el-button>
        </div>
      </div>
    </el-scrollbar>
    <!-- 中间手机区域 -->
    <div class="content" @click.self="selectedDevice = 999">
      <div v-if="isImg" class="video-container" v-for="(device, index) in deviceInformation" :key="device.deviceId">
        <div class="video-canvas" :class="{ active: selectedDevice === index }" :style="getCanvasStyle(index)"
          @click="selectDevice(index)">
          <img class="stream" :src="'http://localhost:' + device.screenPort" />
          <canvas v-show="selectedDevice === index" class="overlay"
            @mousedown.stop="(e) => onCanvasDown(device.deviceId, e, index)"
            @mouseup.stop="(e) => onCanvasUp(device.deviceId, e, index)"
            @mousemove.stop="(e) => onCanvasMove(device.deviceId, e, index)" />
        </div>
        <div class="input-info" v-show="selectedDevice == index">

          <div class="app-button" @click="getMesList(device.deviceId)">获取当前聊天记录</div>
          <!-- <div class="app-button" @click="mqSend()">mq</div> -->
          <!-- <div class="app-button"
            @click="wsActions.clickCopyList(device.deviceId, index); openShowChat = true; istranslate = true">
            翻译本页对话</div>
          <div class="app-button" @click="wsActions.clickCopyList(device.deviceId, index); openShowChat = true;">
            回复消息</div>
          <div class="app-button" @click="wsActions.test(device.deviceId, index)">打印ui节点树</div>
          <div class="app-button" @click="wsActions.isOneLive(device.deviceId, index)">判断单人还是双人</div>
          <div class="app-button" @click="wsActions.slideDown(device.deviceId, index)">下滑</div>
          <div class="app-button" @click="wsActions.killNow(device.deviceId, index)">关闭当前应用</div>
          <div class="app-button" @click="chooseFile(device.deviceId, index, 1, wsActions)">安装 APK
            文件</div>
          <div class="app-button" @click="chooseFile(device.deviceId, index, 2, wsActions)">
            传送文件</div> -->
          <!-- <div style="display: flex;">
            <input style="border: 1px solid #000;margin:0px 14px;" v-model="textContent[index]" type="text"></input>
            <div class="app-button" style="margin: 0px;height: 40px;width: 60px;font-size: 14px;"
              @click="setComText(index)">发送
            </div>
          </div> -->
        </div>
      </div>
    </div>
    <div class="right center-justify" @click.self="selectedDevice = 999">
      <!-- <div style="margin: 30px;"></div> -->
      <ChatDialog :visible="openShowChat" :messages="chatList" />
    </div>
    <MultiLineInputDialog v-model:visible="showDialog" :initialText='""' :title="dialogTitle" :index="selectedDevice"
      @confirm="onDialogConfirm" @cancel="stopAll" />
    <HostListManagerDialog v-model:visible="showHostDlg" @save="onHostSaved" />
  </div>

  <!-- 定时调度配置弹窗 -->
  <el-dialog v-model="showScheduleDlg" title="定时调度（每小时）" width="420px">
    <div style="display:grid;grid-template-columns: 100px 1fr; gap:12px; align-items:center;">
      <div>片段 A</div>
      <div style="display:flex; gap:8px; align-items:center;">
        <el-select v-model="schedAKey" style="width:140px;">
          <el-option label="一键关注" value="follow" />
          <el-option label="刷视频(养号)" value="like" />
          <el-option label="刷直播" value="brushLive" />
          <el-option label="监测消息" value="listen" />
        </el-select>
        <el-input-number v-model="schedAMin" :min="1" :max="59" />
        <span>分钟</span>
      </div>

      <div>片段 B</div>
      <div style="display:flex; gap:8px; align-items:center;">
        <el-select v-model="schedBKey" style="width:140px;">
          <!-- <el-option label="一键关注" value="follow" /> -->
          <el-option label="刷视频(养号)" value="like" />
          <el-option label="刷直播" value="brushLive" />
          <el-option label="监测消息" value="listen" />
        </el-select>
        <el-input-number v-model="schedBMin" :min="1" :max="59" />
        <span>分钟</span>
      </div>

      <div>总时长</div>
      <div><b>{{ schedAMin + schedBMin }}</b> 分钟（必须等于 60）</div>

      <!-- <div>启用调度</div>
      <div><el-switch v-model="scheduleEnabled" /></div> -->
    </div>

    <template #footer>
      <el-button @click="showScheduleDlg = false">取消</el-button>
      <el-button type="primary" @click="saveSchedule">开启</el-button>
    </template>
  </el-dialog>



</template>

<script setup>
import { ref, onMounted, onUnmounted, onBeforeUnmount, watch, inject, computed } from "vue";
import { useRouter } from 'vue-router';
import {
  setphoneXYinfo, getphoneXYinfo, getUser,
  getHostList, setHostList, getContentpriList,
  setContentpriList, getContentList, setContentList,
  setsessionId, getsessionId
} from '@/stores/storage'
import { connectSSE } from '@/utils/sseUtils'
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import { chat, translationToChinese, translation } from "@/api/chat";
import HostListManagerDialog from '@/components/HostListManagerDialog.vue'
import MultiLineInputDialog from '@/components/MultiLineInputDialog.vue'; // 根据实际路径修改
import ChatDialog from '@/components/ChatDialog.vue'
import { pickTikTokBundleId } from '@/utils/arrUtils'
import { logout } from '@/api/account';
import {
  getDeviceList,
  toHome,
  swipeAction,
  tapAction,
  growAccount,
  stopScript,
  watchLiveForGrowth,
  monitorMessages,
  passAnchorData,
  addTempAnchorData,
  deviceAppList,
  launchApp,
  getChatTextInfo,
  setLoginInfo,


} from '@/api/ios';
const router = useRouter();
const openShowChat = ref([true])
//主播库
const showHostDlg = ref(false)

let hostList = []
//查询列表轮询
let getListtimer = null;
let userdata = getUser();
let chatList = ref([])
let isImg = ref(true)
// 引入刷新方法
const reload = inject("reload")
const reloadImg = () => {
  isImg.value = false
  setTimeout(() => {
    isImg.value = true
  }, 1000)
}
//start弹窗
let isMsgPop = ref(false)
//缓存主播联动数组
let stroageHost = ref([])
let runType = ref('')
let isMonitorOn = ref(false)
const hoverIndex = ref(null)  //选中
let showDialog = ref(false);//弹窗是否显示
let dialogTitle = ref('');//当前弹窗类型
let deviceInformation = ref([])
// 你可以用这种方式声明按钮们
//联动用作标记
let batchMode = ref('init');         // 'init' | 'follow'（仅作标记）

// 当前是否被其它模式占用（四个互斥按钮专用）
const isLocked = (type) => !!runType.value && runType.value !== type

// 互斥按钮的样式：激活=红，锁定=半透明且禁点
const ctrlStyle = (type) => ({
  backgroundColor: runType.value === type ? 'red' : '',
  opacity: isLocked(type) ? 0.5 : 1,
  pointerEvents: isLocked(type) ? 'none' : 'auto',
  cursor: isLocked(type) ? 'not-allowed' : 'pointer',
})

const buttons = [
  {
    label: '刷新',
    onClick: () => reloadImg(),
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn1.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn1-1.png', import.meta.url).href
    }
  },
  {
    label: '打开tiktok',
    onClick: () => openTk(),
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn2.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn2-2.png', import.meta.url).href
    }
  },
  {
    label: '返回主页',
    onClick: () => {
      deviceInformation.value.forEach((item) => {
        toHome({ udid: item.deviceId })
      })
    },
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn3.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn3-3.png', import.meta.url).href
    }
  },
  {
    label: '刷直播',
    onClick: () => {
      if (runType.value == 'brushLive') {
        deviceInformation.value.forEach((item) => {
          stopScript({ udid: item.deviceId })
        })
        runType.value = ''
        return
      };

      // 若被其它模式占用：直接返回（已在样式层禁点，这里双保险）
      if (isLocked('brushLive')) return

      runType.value = 'brushLive'
      deviceInformation.value.forEach((item) => watchLiveForGrowth({ udid: item.deviceId }))
    },
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn4.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn4-4.png', import.meta.url).href
    },
    style: () => ctrlStyle('brushLive')

  },
  {
    label: '刷视频',
    onClick: () => {
      if (runType.value == 'like') {
        deviceInformation.value.forEach((item) => {
          stopScript({ udid: item.deviceId })
        })
        runType.value = ''
        return
      };

      if (isLocked('like')) return

      runType.value = 'like'
      deviceInformation.value.forEach((item) => growAccount({ udid: item.deviceId }))
    },
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn5.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn5-5.png', import.meta.url).href
    },
    style: () => ctrlStyle('like')
  },
  // {
  //   label: '一键关注并打招呼',
  //   onClick: () => {

  //     if (runType.value == 'follow') {
  //       deviceInformation.value.forEach((item) => {
  //         stopScript({ udid: item.deviceId })
  //       })
  //       runType.value = ''
  //       return
  //     };

  //     if (isLocked('follow')) return
  //     showDialog.value = true;
  //     dialogTitle.value = '主播ID';

  //   },
  //   show: () => true,
  //   img: {
  //     normal: new URL('@/assets/video/leftBtn6.png', import.meta.url).href,
  //     hover: new URL('@/assets/video/leftBtn6-6.png', import.meta.url).href
  //   },
  //   style: () => ctrlStyle('follow')

  // },
  {
    label: '启动调度任务',
    onClick: () => openScheduleDialog(),
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn6.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn6-6.png', import.meta.url).href
    },
    style: () => ctrlStyle('follow')

  },
  {
    label: '监测消息',
    onClick: () => {
      if (runType.value == 'lisen') {
        deviceInformation.value.forEach((item) => {
          stopScript({ udid: item.deviceId })
        })
        runType.value = ''
        return
      };
      if (isLocked('lisen')) return

      runType.value = 'lisen'
      deviceInformation.value.forEach((item) => monitorMessages({ udid: item.deviceId }))
    },
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn1.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn1-1.png', import.meta.url).href
    },
    style: () => ctrlStyle('lisen')

  },
  // {
  //   label: '定时调度',
  //   onClick: () => openScheduleDialog(),
  //   show: () => true,
  //   img: {
  //     normal: new URL('@/assets/video/leftBtn1.png', import.meta.url).href,
  //     hover: new URL('@/assets/video/leftBtn1-1.png', import.meta.url).href
  //   }
  // },
  {
    label: '全部停止',
    onClick: () => stopAll(),
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn8.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn8-8.png', import.meta.url).href
    },

  },
  {
    label: '登出',
    onClick: () => {
      logout({ userId: userdata.id, tenantId: userdata.tenantId })
      router.push('/')

    },
    show: () => true,
    img: {
      normal: new URL('@/assets/video/leftBtn9.png', import.meta.url).href,
      hover: new URL('@/assets/video/leftBtn9-9.png', import.meta.url).href
    }
  }
]
const schedulePlan = [
  { key: 'follow', duration: 40 * 60 * 1000 },
  { key: 'like', duration: 20 * 60 * 1000 },
]
// 调度状态（持久化一下，避免刷新丢失）
let scheduleState = (() => {
  try {
    const saved = JSON.parse(localStorage.getItem('SCHEDULE_STATE') || '{}')
    if (saved && typeof saved.index === 'number' && typeof saved.startTime === 'number') {
      return saved
    }
  } catch { }
  return { index: 0, startTime: Date.now() }
})()

let scheduleTimer = null      // 轮询定时器句柄
const scheduleTickMs = 30_000 // 每 30s 检查一次是否到切换点
let scheduleEnabled = ref(false)    // 需要时可手动关闭调度（例如“全部停止”）
// 弹窗
const showScheduleDlg = ref(false)

// 两个时间片（默认 A=follow 40min，B=like 20min）
const schedAKey = ref('follow')
const schedAMin = ref(40)
const schedBKey = ref('like')
const schedBMin = ref(20)
// 打开弹窗：把当前 schedulePlan 映射到 UI
function openScheduleDialog() {
  // 把当前计划读出来（只支持两个片段的简易版）
  if (Array.isArray(schedulePlan) && schedulePlan.length >= 2) {
    const a = schedulePlan[0], b = schedulePlan[1]
    schedAKey.value = a?.key || 'follow'
    schedAMin.value = Math.max(1, Math.round((a?.duration || 40 * 60_000) / 60_000))
    schedBKey.value = b?.key || 'like'
    schedBMin.value = Math.max(1, Math.round((b?.duration || 20 * 60_000) / 60_000))
  }
  showScheduleDlg.value = true
}

// 保存：校验=60 分钟 → 更新 schedulePlan → 持久化 → 重启轮询
function saveSchedule() {

  const total = schedAMin.value + schedBMin.value
  if (total !== 60) {
    ElMessage.error('两个片段相加必须等于 60 分钟')
    return
  }
  schedulePlan.splice(0, schedulePlan.length,
    { key: schedAKey.value, duration: schedAMin.value * 60_000 },
    { key: schedBKey.value, duration: schedBMin.value * 60_000 },
  )

  // 存 localStorage
  localStorage.setItem('SCHEDULE_PLAN', JSON.stringify(schedulePlan))
  localStorage.setItem('SCHEDULE_ENABLED', JSON.stringify(!!scheduleEnabled.value))

  // 重置时间片起点并立即生效
  scheduleState.index = 0
  scheduleState.startTime = Date.now()
  localStorage.setItem('SCHEDULE_STATE', JSON.stringify(scheduleState))

  // 若启用则重启轮询
  startScheduleLoop()

  showScheduleDlg.value = false
  ElMessage.success('已保存定时调度')
}

const selectedDevice = ref(null)

// —— 显示尺寸固定为 320x720；未选中缩略为 THUMB_SCALE 倍 ——
// 尺寸与排布
const BASE_W = 320
const BASE_H = 720
const THUMB_SCALE = 0.6
const PER_ROW = 3

// 底行上移的位移量：720*(1-0.6)=288
const BOTTOM_SHIFT = Math.round(BASE_H * (1 - THUMB_SCALE)) // 288

// 是否至少有两行
const hasTwoRows = computed(() => deviceInformation.value.length > PER_ROW)

// 真正的“底行”判定：必须有两行以上才成立
const isBottomRow = (index) => {
  if (!hasTwoRows.value) return false
  const lastRow = Math.floor((deviceInformation.value.length - 1) / PER_ROW)
  return Math.floor(index / PER_ROW) === lastRow
}

// 统一给 .video-canvas 返回 transform（缩略/放大/底行上移）
function getCanvasStyle(index) {
  const isSelected = selectedDevice.value === index
  if (!isSelected) {
    return { transform: `scale(${THUMB_SCALE})` }
  }
  // 选中：默认正常放大；若在底行且至少两行 -> 先上移再放大
  return isBottomRow(index)
    ? { transform: `translateY(-${BOTTOM_SHIFT}px) scale(1)` }
    : { transform: 'scale(1)' }
}
// 当前选中的卡片：选中=1倍，未选中=缩略比例
const imgWH = (index) => {
  const scale = (selectedDevice.value === index) ? 1 : THUMB_SCALE
  return {
    width: `${BASE_W * scale}px`,
    height: `${BASE_H * scale}px`,
    transition: 'all 0.3s ease',
  }
}

// 计算某索引当前展示宽高（用于坐标换算）
const displaySize = (index) => {
  const scale = (selectedDevice.value === index) ? 1 : THUMB_SCALE
  return { w: BASE_W * scale, h: BASE_H * scale }
}

// 从 Canvas offset 坐标 → 真实手机分辨率坐标
const mapToDeviceXY = (index, offsetX, offsetY) => {
  const dev = deviceInformation.value[index] || {}
  const realW = Number(dev.width) || BASE_W   // 后端返回的真实分辨率
  const realH = Number(dev.height) || BASE_H
  const rotation = Number(dev.rotation || 0)   // 若后端有提供旋转角，可用 0/90/180/270

  const { w: dispW, h: dispH } = displaySize(index)

  // 归一化到 0~1
  let nx = Math.min(Math.max(offsetX / dispW, 0), 1)
  let ny = Math.min(Math.max(offsetY / dispH, 0), 1)

  // 处理旋转（如果你的服务器坐标基于设备原生朝向）
  // 0: 直接映射；90: 顺时针；180、270 同理
  let x, y
  switch (rotation % 360) {
    case 90:
    case -270:
      x = Math.round(ny * realW)
      y = Math.round((1 - nx) * realH)
      break
    case 180:
    case -180:
      x = Math.round((1 - nx) * realW)
      y = Math.round((1 - ny) * realH)
      break
    case 270:
    case -90:
      x = Math.round((1 - ny) * realW)
      y = Math.round(nx * realH)
      break
    default: // 0°
      x = Math.round(nx * realW)
      y = Math.round(ny * realH)
  }
  return { x, y }
}

// 选中：恢复到 320x720 并显示盖层
const selectDevice = (index) => {
  selectedDevice.value = index
}

// ——— 鼠标交互：按下/移动/抬起 ———
const dragState = ref({}) // 以 index 作为 key 保存 {ox, oy, t}

const onCanvasDown = (udid, e, index) => {
  // 记录起点（Canvas 内的 offset）
  dragState.value[index] = { ox: e.offsetX, oy: e.offsetY, t: Date.now(), udid }
}

const onCanvasMove = (udid, e, index) => {
  // 如需在 overlay 上画指示、十字线等，可在这里使用 e.offsetX/e.offsetY
}

const onCanvasUp = async (udid, e, index) => {
  const st = dragState.value[index]
  if (!st) return

  const { ox, oy, t } = st
  const dx = e.offsetX - ox
  const dy = e.offsetY - oy
  const elapsed = Date.now() - t
  delete dragState.value[index]

  // 映射到真实分辨率
  const p0 = mapToDeviceXY(index, ox, oy)
  const p1 = mapToDeviceXY(index, e.offsetX, e.offsetY)
  console.log(" x, y", p0, p1)
  // 判断是“点按”还是“滑动”
  const MOVE_THR = 5    // 像素阈值（可按需调整）
  const isTap = Math.hypot(dx, dy) < MOVE_THR && elapsed < 500

  try {
    if (isTap) {
      await tapAction({ udid, x: p1.x, y: p1.y })
      // console.log('tap', p1)
    } else {
      // 只需要方向：1上/2左/3下/4右
      const rotation = Number((deviceInformation.value[index] || {}).rotation || 0)

      const code = getSwipeCodeWithRotation(dx, dy, rotation)  // 必定得到1~4
      console.log("code", code)
      await swipeAction({ udid, direction: code })

    }
  } catch (err) {
    console.error(err)
  }
}

/** 方向码：1=上, 2=左, 3=下, 4=右（不返回0，始终给出一个方向） */
function getSwipeCode(dx, dy) {
  // 哪个轴位移更大就取哪个轴；边界≈45°
  if (Math.abs(dx) >= Math.abs(dy)) {
    return dx < 0 ? 2 : 4  // 左/右
  } else {
    return dy < 0 ? 1 : 3  // 上/下（DOM坐标里向上是负）
  }
}

/** 带设备旋转(0/90/180/270)：先把画布向量(dx,dy)旋回设备坐标系再判方向 */
function getSwipeCodeWithRotation(dx, dy, rotation = 0) {
  let dxD = dx, dyD = dy
  switch ((rotation % 360 + 360) % 360) {
    case 90: dxD = dy; dyD = -dx; break
    case 180: dxD = -dx; dyD = -dy; break
    case 270: dxD = -dy; dyD = dx; break
    default: break
  }
  return getSwipeCode(dxD, dyD)
}



async function openTk() {
  if (!deviceInformation.value?.length) {
    ElMessage.warning('暂无在线设备')
    return
  }

  const loading = ElLoading.service({ text: '正在打开 TikTok …', background: 'rgba(0,0,0,.35)' })
  const results = []

  try {
    // 为了稳妥，逐台串行（如果你希望更快，可改 Promise.all 并注意并发数）
    for (const dev of deviceInformation.value) {
      const udid = dev.deviceId
      try {
        const apps = await deviceAppList({ udid }) // 期望返回示例中的数组
        const bundleId = pickTikTokBundleId(apps)

        if (!bundleId) {
          results.push({ udid, ok: false, msg: '未找到 TikTok' })
          continue
        }

        await launchApp({ udid, bundleId })
        results.push({ udid, ok: true, msg: `已启动 TikTok (${bundleId})` })
      } catch (e) {
        console.error('openTk error', udid, e)
        results.push({ udid, ok: false, msg: '请求失败' })
      }
    }
  } finally {
    loading.close()
  }

  // 汇总提示（成功/失败各一条）
  const okCount = results.filter(r => r.ok).length
  const fail = results.filter(r => !r.ok)
  if (okCount) ElMessage.success(`已在 ${okCount} 台设备启动 TikTok`)
  if (fail.length) {
    const udids = fail.map(f => f.udid).join(', ')
    ElMessage.error(`以下设备未能启动：${udids}`)
  }
}

function getMesList(deviceId) {
  getChatTextInfo({ udid: deviceId }).then((res) => {
    if (res) {
      chatList.value = res
      console.log(chatList.value)
      getTranslation(chatList.value)
    }
  })
}

function stopAll() {
  // if (!runType.value) return
  deviceInformation.value.forEach((item) => {
    stopScript({ udid: item.deviceId }).then((res) => {
      console.log(`停止成功：${item.deviceId}`, res, printCurrentTime())
      ElMessage.success(`停止成功：${item.deviceId}`)
    }).catch((res) => {
      console.log(`停止失败`, printCurrentTime())
      ElMessage.error(`脚本已停止`)
    })
  })
  scheduleEnabled.value = false
  runType.value = ''
  batchMode.value = 'init';
}

//确认多行文本框内容
function onDialogConfirm(result, type, index, isMon) {
  // console.log(type, result, isMon);
  if (type == '主播ID') {
    hostList = (result || []).map(id => ({ id, country: '' }))

    dialogTitle.value = '私信';
    setTimeout(() => {
      showDialog.value = true;
    }, 600)
  } else if (type == '私信') {
    runType.value = 'follow'
    setContentpriList(result)
    passAnchorData(
      {
        deviceList: deviceInformation.value.map(item => item.deviceId),
        anchorList: hostList.map(item => ({
          anchorId: item.id,
          country: item.country
        })),
        prologueList: result,
        needReply: isMon
      }
    ).then((res) => {
      hostList = []
    })
  }


}

onMounted(() => {
  const loading = ElLoading.service({
    lock: true,
    text: 'Loading',
    background: 'rgba(0, 0, 0, 0.7)',
  });
  getDeviceListFun()
  window.electronAPI.startMq(userdata.tenantId, userdata.id)
  // 初始化时获取设备列表
  getListtimer = setInterval(() => {
    loading.close();
    getDeviceListFun()
  }, 3000)



  // 批次缓冲（仅用于当前“波”）
  let batch = [];                 // [{ country, text }]
  let flushTimer = null;

  function scheduleFlush(handler, delay = 400) {
    if (flushTimer) clearTimeout(flushTimer);
    flushTimer = setTimeout(() => {
      if (batch.length) {
        const items = batch.slice(); // 拷贝一份
        batch.length = 0;            // 清空批次
        try {
          handler(items);
        } catch (e) {
          console.error('[SSE flush error]', e);
          // 出错不回灌，避免重复提交；必要时可根据需要 batch.push(...items)
        }
      }
    }, delay);
  }

  // —— SSE 接收 —— 
  const es = connectSSE('http://localhost:3312/events', (data) => {
    console.log('来自服务端:', data);

    if (data === 'start') {
      // 新一波开始：根据当前状态决定“本波 flush 用谁”
      if (!isMsgPop.value) {
        // 还没开始过 -> 首次弹框，确认后使用处理本波
        isMsgPop.value = true;
        batchMode.value = 'init';
        ElMessageBox.confirm(
          '检测到YOLO助手正在爬取主播，是否进行操作？',
          '消息提醒',
          { confirmButtonText: '开始', cancelButtonText: '取消', type: 'success' }
        )
          .then(() => {
            ElMessage({ type: 'success', message: '任务开启成功' });
            // runType.value = 'follow';
            batchMode.value = 'follow';

            // 不在这里立刻提交；让后续主播数据先进 batch，再由防抖统一 flush
            // 不直接发；把这“一波”的主播先塞进 hostList，然后弹出“私信”输入框
            scheduleFlush((items) => {
              hostList = (items || []).map(h => ({ id: h.text, country: h.country || '' }))
              showScheduleDlg.value = true
            })
          })
          .catch(() => {
            // 取消：清理状态，丢弃批次
            batch.length = 0;
            isMsgPop.value = false;
          });
      } else {
        // 已经在运行 follow：本波用 addTempAnchorData 追加
        batchMode.value = 'follow';
        // 立刻安排一次“尾随防抖”flush，等本波数据齐了再送
        scheduleFlush((items) => {
          addTempAnchorData(items.map(h => ({ anchorId: h.text, country: h.country || '' })));
        });
      }
    } else {
      // 非 start：本波主播数据进入批次
      const country = data && data.country != null ? data.country : '';
      const text = data && (data.hostsId != null ? data.hostsId : data.text);
      if (text == null) {
        // 数据格式不对，丢弃或打印
        console.warn('[SSE] 非法数据，缺少 hostsId/text:', data);
        return;
      }
      batch.push({ country, text });

      // 根据当前模式，刷新防抖（让“最后一条到来后”延迟几百毫秒再统一提交）
      if (batchMode.value === 'init') {
        // 首次确认前：等用户点“开始”后由上面的 scheduleFlush 执行 
        scheduleFlush((items) => {
          // 安全起见：只有在 runType 已经 follow 时才真正提交
          if (runType.value === 'follow') {
            passAnchorData({
              deviceList: deviceInformation.value.map(item => item.deviceId),
              anchorList: items.map(h => ({ anchorId: h.text, country: h.country || '' })),
              needReply: false
            });
          } else {
            // 还没开始就来了数据：把它们留回批次，等待上面 then 里的 scheduleFlush 再处理
            batch.push(...items);
          }
        });
      } else {
        // 已在关注：走追加逻辑
        scheduleFlush((items) => {
          addTempAnchorData(items.map(h => ({ anchorId: h.text, country: h.country || '' })));
        });
      }
    }
  });


})

onUnmounted(() => {
  clearInterval(getListtimer)
  getListtimer = null
})
const getDeviceListFun = () => {
  getDeviceList().then((res) => {
    console.log('返回', res.length)
    if (res && res.length > 0 && deviceInformation.value.length !== res.length) {
      console.log("设备变更")
      deviceInformation.value = res
      reloadImg()
    }

    if (res.length == 0) {
      deviceInformation.value = []
      reloadImg()
    }
    // deviceInformation.value = ['', '', '', '', '', '',]
  }).catch((err) => {
    ElMessage.error(`IOSAI服务错误`)

  })
}

async function uploadLogFile() {
  let loading = null
  try {
    // 先弹出确认框
    await ElMessageBox.confirm(
      '确定要上传日志文件吗？',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }
    )
    // 如果点了确定，就会走到这里
    loading = ElLoading.service({
      lock: true,
      text: '上传中...',
      background: 'rgba(0, 0, 0, 0.7)',
    })
    const res = await setLoginInfo({
      "tenantId": userdata.tenantId,
      "userId": userdata.id,
      "token": userdata.tokenValue
    })
    loading.close()
    console.log("上传文件返回", res)
    if (res) {
      console.log("✅ 上传成功:", res)
      ElMessage.success('✅ 上传成功')
    } else {
      console.error("❌ 上传失败:", res.msg)
      ElMessage.error('❌ 上传失败: ' + (res.msg || '未知错误'))
    }
  } catch (err) {
    if (loading) {
      loading.close()
    }
    // 如果用户点了取消，会进入这里
    if (err === 'cancel' || err === 'close') {
      ElMessage.info('已取消上传')
    } else {
      console.error("❌ 上传异常:", err)
      ElMessage.error('❌ 上传异常: ' + err)
    }

  }
}
function runTask(key) {
  console.log('[schedule] 切换到任务:', key, printCurrentTime())

  forceActivate(key, () => {
    if (key === 'follow') {


      if (scheduleEnabled.value) {
        stopAll()
        setTimeout(() => {
          runType.value = 'follow'

          passAnchorData(
            {
              deviceList: deviceInformation.value.map(item => item.deviceId),
              anchorList: [],
              prologueList: getContentpriList(),
              needReply: false
            }
          ).then((res) => {
            hostList = []
          })
        }, 1000)

        return
      }

      scheduleEnabled.value = true
      if (hostList.length <= 0) {
        dialogTitle.value = '主播ID';
      } else {
        dialogTitle.value = '私信';
      }
      showDialog.value = true;

    } else if (key === 'like') {

      stopAll()

      setTimeout(() => {
        scheduleEnabled.value = true
        runType.value = 'like'
        deviceInformation.value.forEach((item) => growAccount({ udid: item.deviceId }))
      }, 1000)

    } else if (key === 'brushLive') {
      stopAll()

      setTimeout(() => {
        scheduleEnabled.value = true
        runType.value = 'brushLive'
        deviceInformation.value.forEach((item) => watchLiveForGrowth({ udid: item.deviceId }))
      }, 1000)
      runType.value = 'brushLive'
    } else if (key === 'listen') {
      stopAll()

      setTimeout(() => {
        runType.value = 'listen'
        scheduleEnabled.value = true
        isMonitorOn.value = true
        deviceInformation.value.forEach((item) => monitorMessages({ udid: item.deviceId }))
      }, 1000)

    }
  })
}

function startScheduleLoop() {
  // 先按照当前 index 跑一次，保证“即刻对齐”
  runTask(schedulePlan[scheduleState.index].key)

  // 清理旧轮询，防止重复
  if (scheduleTimer) clearInterval(scheduleTimer)

  scheduleTimer = setInterval(() => {
    if (!scheduleEnabled.value) return

    const now = Date.now()
    const cur = schedulePlan[scheduleState.index]
    const elapsed = now - scheduleState.startTime

    if (elapsed >= cur.duration) {
      // 进入下一个时间片
      scheduleState.index = (scheduleState.index + 1) % schedulePlan.length
      scheduleState.startTime = now
      localStorage.setItem('SCHEDULE_STATE', JSON.stringify(scheduleState))

      runTask(schedulePlan[scheduleState.index].key)
    }
  }, scheduleTickMs)
}

function forceActivate(key, runner) {
  // 跳过互斥逻辑，直接切换
  runType.value = key;
  if (typeof runner === 'function') runner();
}


function mqSend() {
  window.electronAPI.mqSend("start")
}


function getTranslation(list) {
  list.forEach((item, index) => {
    translationToChinese({ msg: item.text }).then(res => {
      console.log(res);
      chatList.value[index].text = res
    })
  })
}

function onHostSaved(list) {
  console.log('保存后的主播id:', list)
}
// //sse接收爬虫发送的消息
// const es = connectSSE(`http://localhost:3311/events`, (data) => {
//   // connectSSE(`http://192.168.1.155:19665/api/sse/connect/${userdata.tenantId}/${userdata.id}`, (data) => {
//   // 处理服务端推送的数据
//   console.log('来自服务端:', data)

//   //接收到start
//   if (data === 'start') {

//   } else {

//   }


// })

//当前时间获取
function printCurrentTime() {
  const now = new Date();
  return now.toLocaleString()
}

</script>

<style scoped lang="less">
@import '../static/css/video.less';
</style>
