import { reactive, markRaw } from 'vue';
import { SignalingClient } from '../services/SignalingClient';
import { WebRtcController } from '../services/WebRtcController';
import { VideoRecorder } from '../services/VideoRecorder';
import { loadProto } from '../proto/controlMessage';
import * as api from '../services/ApiClient';

// 远程视频录制器（基于浏览器原生 MediaRecorder）。
const videoRecorder = new VideoRecorder();

// 兜底 ICE 服务器：当服务端未返回 TURN 凭证时使用（仅 STUN，可能穿透失败）。
// 来自 .env 的 VITE_FALLBACK_ICE（多个以 ; 分隔），未配置则使用内置默认值。
function parseFallbackIce() {
  const raw = (import.meta.env.VITE_FALLBACK_ICE || '').trim();
  if (raw) {
    return raw
      .split(';')
      .map((s) => s.trim())
      .filter(Boolean)
      .map((urls) => ({ urls }));
  }
  return [
    { urls: 'stun:175.178.213.60:3478' },
    { urls: 'stun:47.242.112.133:3478' },
  ];
}
export const FALLBACK_ICE_SERVERS = parseFallbackIce();

// 信令 WebSocket 地址：服务端 WebSocketConfig 注册的路径为 /ws/signal，
// 子协议 signal.v1（令牌通过 auth.<token> 子协议携带）。
// 优先 VITE_WS_URL；其次由 VITE_API_BASE 推导（http(s) -> ws(s) + /ws/signal）；
// 两者皆空则回退到生产域名，保证未配置 .env 时也不崩。
const DEFAULT_WS_URL = (() => {
  if (import.meta.env.VITE_WS_URL) return import.meta.env.VITE_WS_URL;
  const base = import.meta.env.VITE_API_BASE;
  if (base) return base.replace(/^http/, 'ws').replace(/\/$/, '') + '/ws/signal';
  return 'wss://www.ttstd.com/ws/signal';
})();

export const store = reactive({
  serverUrl: DEFAULT_WS_URL,

  // 登录态
  loggedIn: api.isLoggedIn(),
  username: '',
  loginError: '',
  loginBusy: false,
  // 会话恢复中（页面刷新后用 /api/auth/me 校验令牌）
  restoring: false,

  // 本机设备 ID 由服务端 REGISTER_SUCCESS 下发，无需用户填写。
  deviceId: '',
  targetDeviceId: '',
  iceServers: FALLBACK_ICE_SERVERS,

  protoReady: false,
  signalingConnected: false,
  signalingConnecting: false,
  registered: false,
  rtcConnected: false,
  dataChannelOpen: false,
  statusText: '未连接',
  error: '',

  // 已绑定设备：[{ bindingId, deviceUid, alias, role, online }]
  controlledDevices: [],
  devicesLoading: false,
  devicesError: '',
  stats: null,
  remoteStream: null,
  currentResolution: null,

  recording: false,
  recordStatus: '',
});

let signaling = null;
let webrtc = null;

// 令牌彻底失效（刷新也失败）时，由 ApiClient 回调此处统一回到登录页。
api.setAuthFailedHandler((reason) => {
  store.error = reason || '登录已过期，请重新登录';
  store.loggedIn = false;
  store.username = '';
  disconnectSignaling();
});

export async function initProto() {
  await loadProto();
  store.protoReady = true;
}

/* ---------------- 登录 / 登出 ---------------- */

export async function login(username, password, totpCode) {
  store.loginBusy = true;
  store.loginError = '';
  try {
    // 服务端 LoginResponse 字段为 displayName，不是 username。
    const data = await api.login(username, password, totpCode);
    store.loggedIn = true;
    store.username = data.displayName || username;
    return true;
  } catch (e) {
    store.loginError = e.message || '登录失败';
    return false;
  } finally {
    store.loginBusy = false;
  }
}

export async function register(username, password) {
  return api.register({ username, password });
}

/**
 * 页面加载时恢复会话：sessionStorage 里有令牌就用 /api/auth/me 校验，
 * 有效则直接进主界面并自动连信令，无效则清理令牌回到登录页。
 */
export async function restoreSession() {
  if (!api.isLoggedIn()) return false;
  store.restoring = true;
  try {
    const info = await api.me();
    store.loggedIn = true;
    store.username = info.displayName || '';
    await connectSignaling();
    return true;
  } catch {
    api.clearTokens();
    store.loggedIn = false;
    store.username = '';
    return false;
  } finally {
    store.restoring = false;
  }
}

export async function logout() {
  // 先断连接再登出，避免服务端已销毁会话后 WS 收到 4003 又触发一次强制登出。
  disconnectSignaling();
  await api.logout().catch(() => {});
  store.loggedIn = false;
  store.username = '';
  store.loginError = '';
}

/* ---------------- 信令连接（Bearer 由子协议携带） ---------------- */

export async function connectSignaling() {
  store.error = '';
  if (!api.isLoggedIn()) { store.error = '请先登录'; return; }

  store.signalingConnecting = true;
  signaling = new SignalingClient({
    serverUrl: store.serverUrl.trim(),
    onConnected: async () => {
      store.signalingConnected = true;
      store.signalingConnecting = false;
      store.statusText = '已连接信令服务器';
      // 登录态下自动拉取一次 TURN 凭证与绑定设备列表。
      await loadTurnCredentials();
      await loadBindings();
    },
    onDisconnected: () => {
      store.signalingConnected = false;
      store.signalingConnecting = false;
      store.registered = false;
      store.statusText = '已断开信令连接';
    },
    onError: (e) => {
      store.signalingConnecting = false;
      store.error = '信令错误: ' + e;
    },
    onMessage: handleSignalMessage,
    // 4001：尝试刷新令牌后重连。
    onTokenExpired: async () => {
      try {
        await api.refresh();
        reconnectSignaling();
      } catch {
        await forceLogout('令牌已失效，请重新登录');
      }
    },
    // 4003：强制下线。
    onForceLogout: async (reason) => {
      await forceLogout(reason || '账号已在其他位置登录');
    },
  });
  signaling.connect();
}

// 刷新令牌后重连（保留已登录态）。
function reconnectSignaling() {
  store.statusText = '令牌已刷新，正在重连...';
  if (signaling) { signaling.disconnect(); signaling = null; }
  connectSignaling();
}

async function forceLogout(reason) {
  store.error = reason;
  await api.logout().catch(() => {});
  store.loggedIn = false;
  store.username = '';
  disconnectSignaling();
}

// 拉取 TURN 短期凭证（服务端开启时覆盖默认 ICE）。
export async function loadTurnCredentials() {
  const data = await api.fetchTurnCredentials();
  if (data && Array.isArray(data.iceServers) && data.iceServers.length) {
    store.iceServers = data.iceServers;
  } else {
    store.iceServers = FALLBACK_ICE_SERVERS;
  }
  return store.iceServers;
}

/**
 * 拉取当前账号已绑定的被控端列表（服务端只返回 status=ACTIVE 的绑定）。
 * 保留 alias / online，供 UI 展示备注名与在线状态。
 * 同时用 /api/client/devices/online 修正在线标记（该接口以实时 WS 会话为准）。
 */
export async function loadBindings() {
  store.devicesLoading = true;
  store.devicesError = '';
  try {
    const data = await api.listBindings();
    const list = (data && data.bindings) || [];

    // 实时在线设备集合（失败时降级为绑定记录里的 online 字段）。
    let onlineSet = null;
    try {
      const od = await api.listOnlineDevices();
      onlineSet = new Set(((od && od.devices) || []).map((d) => d.deviceUid || d));
    } catch { /* 降级 */ }

    store.controlledDevices = list
      .map((b) => {
        if (typeof b === 'string') return { deviceUid: b, alias: '', online: false };
        const uid = b.deviceUid || b.deviceId || '';
        return {
          bindingId: b.bindingId,
          deviceUid: uid,
          alias: b.alias || '',
          role: b.role || '',
          online: onlineSet ? onlineSet.has(uid) : !!b.online,
        };
      })
      .filter((d) => d.deviceUid);

    // 目标设备已被解绑时清空选择。
    if (store.targetDeviceId &&
        !store.controlledDevices.some((d) => d.deviceUid === store.targetDeviceId)) {
      store.targetDeviceId = '';
    }
  } catch (e) {
    store.controlledDevices = [];
    store.devicesError = e.message || '获取绑定设备失败';
  } finally {
    store.devicesLoading = false;
  }
}

/** 用被控端出示的配对码绑定新设备，成功后刷新列表。 */
export async function bindByPairingCode(code, alias) {
  const res = await api.redeemPairingCode(code, alias);
  await loadBindings();
  return res;
}

function handleSignalMessage(msg) {
  switch ((msg.type || '').toUpperCase()) {
    case 'REGISTER_SUCCESS':
      store.registered = true;
      store.deviceId = msg.fromDeviceId || store.deviceId;
      store.statusText = '注册成功 (CONTROLLER)';
      break;
    case 'DEVICE_LIST': {
      // 服务端推送在线设备变动时，仅刷新已绑定列表的在线标记，
      // 不直接覆盖（DEVICE_LIST 不含 alias/绑定关系）。
      loadBindings();
      break;
    }
    case 'ANSWER': {
      store.statusText = '被控端已接受，正在建立连接...';
      if (webrtc) {
        webrtc.handleAnswer(parsePayload(msg.payload).sdp).catch((e) => {
          store.error = '设置远端描述失败: ' + (e?.message || e);
        });
      }
      break;
    }
    case 'ICE_CANDIDATE':
      webrtc && webrtc.handleIceCandidate(parsePayload(msg.payload));
      break;
    case 'TARGET_OFFLINE':
      store.error = msg.payload || '目标被控端不在线，请确认设备已开启并连接服务器';
      store.statusText = '连接失败';
      break;
    case 'CONNECTION_REJECTED':
    case 'REQUEST_ERROR':
    case 'REQUEST_TIMEOUT':
      store.error = msg.payload || '连接请求失败';
      store.statusText = '连接被拒绝';
      break;
  }
}

export function refreshDevices() {
  loadBindings();
}

export async function connectToDevice(targetId, authType = null, authValue = null) {
  if (!signaling || !store.signalingConnected) { store.error = '请先连接信令服务器'; return; }
  if (!targetId) { store.error = '请选择要控制的被控端设备'; return; }

  store.targetDeviceId = targetId;
  store.error = '';
  store.statusText = '正在发起连接...';
  store.recording = false;
  store.recordStatus = '';

  if (webrtc) {
    if (videoRecorder.recording) await stopRecording();
    await webrtc.close();
    webrtc = null;
  }

  try {
    webrtc = new WebRtcController({
      iceServers: store.iceServers,
      deviceId: store.deviceId,
      targetDeviceId: targetId,
      signaling,
      onIceState: (s) => {
        if (s === 'connected') { store.rtcConnected = true; store.statusText = '已连接，可远程控制'; }
        else if (s === 'disconnected' || s === 'failed') { store.rtcConnected = false; store.statusText = '连接已断开'; }
      },
      onDataChannelState: (open) => { store.dataChannelOpen = open; },
      onStream: (stream) => { store.remoteStream = markRaw(stream); },
      onStats: (stats) => { store.stats = stats; },
      onError: (msg) => { if (msg) store.error = msg; },
      onResolutionReport: (res) => { store.currentResolution = res; },
    });
    await webrtc.createOffer(authType, authValue);
  } catch (e) {
    console.error('[connectToDevice] 创建 Offer 失败:', e);
    store.error = '创建连接失败: ' + (e?.message || e);
    store.statusText = '连接失败';
    if (webrtc) { await webrtc.close(); webrtc = null; }
  }
}

export async function disconnectDevice() {
  if (videoRecorder.recording) {
    await stopRecording();
  }
  if (webrtc) { await webrtc.close(); webrtc = null; }
  store.rtcConnected = false;
  store.dataChannelOpen = false;
  store.remoteStream = null;
  store.stats = null;
  store.currentResolution = null;
  store.recording = false;
  store.statusText = store.signalingConnected ? '已断开设备连接' : '未连接';
}

export function toggleRecording() {
  if (store.recording) return stopRecording();
  return startRecording();
}

export function startRecording() {
  if (store.recording) return;
  if (!store.remoteStream) {
    store.error = '尚未接收到视频画面，无法录制';
    return;
  }
  if (!videoRecorder.isSupported) {
    store.error = '当前浏览器不支持 MediaRecorder 录制';
    return;
  }
  try {
    const ok = videoRecorder.start(store.remoteStream);
    if (ok) {
      store.recording = true;
      store.recordStatus = '录制中…';
    }
  } catch (e) {
    store.recordStatus = '';
    store.error = '开始录制失败: ' + (e?.message || e);
  }
}

export async function stopRecording() {
  const result = await videoRecorder.stop();
  store.recording = false;
  if (result) {
    const a = document.createElement('a');
    a.href = result.url;
    a.download = result.filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    store.recordStatus = '已保存：' + result.filename;
    setTimeout(() => URL.revokeObjectURL(result.url), 30000);
  } else {
    store.recordStatus = '录制已停止';
  }
  return result;
}

export function disconnectSignaling() {
  disconnectDevice();
  if (signaling) { signaling.disconnect(); signaling = null; }
  store.signalingConnected = false;
  store.signalingConnecting = false;
  store.registered = false;
  store.controlledDevices = [];
}

// 控制指令转发（供 UI 组件调用）
export function sendTouch(x, y) { return webrtc && webrtc.sendTouch(x, y); }
export function sendSwipe(x1, y1, x2, y2, duration) { return webrtc && webrtc.sendSwipe(x1, y1, x2, y2, duration); }
export function sendLongPress(x, y) { return webrtc && webrtc.sendLongPress(x, y); }
export function sendMotionEvent(action, x, y) { return webrtc && webrtc.sendMotionEvent(action, x, y); }
export function sendKey(keyCode) { return webrtc && webrtc.sendKey(keyCode); }
export function sendKeyDown(keyCode) { return webrtc && webrtc.sendKeyDown(keyCode); }
export function sendKeyUp(keyCode) { return webrtc && webrtc.sendKeyUp(keyCode); }
export function sendResolutionChange(width, height, fps) { return webrtc && webrtc.sendResolutionChange(width, height, fps); }

function parsePayload(payload) {
  if (!payload) return {};
  if (typeof payload === 'string') {
    try { return JSON.parse(payload); } catch { return {}; }
  }
  return payload;
}
