const MEDIA_HEADER_SIZE = 26;
const MEDIA_MAGIC = [0x43, 0x4d, 0x56, 0x46]; // CMVF
const MEDIA_MIME_TYPES = {
  1: 'video/mp4; codecs="avc1.42C01E"'
};

class WebSocketManager {
  constructor(url, userId) {
    this.url = url;
    this.userId = userId;
    this.ws = null;
    this.events = {};
    this.reconnectTimer = null;
    this.heartbeatTimer = null;
    this.isManualClose = false;
    this.messageQueue = [];
    this.processingMessages = false;
    this.maxQueueSize = 100;
    this.status = false;
  }

  connect() {
    if (!window.WebSocket) {
      console.error('浏览器不支持 WebSocket');
      return;
    }

    this.ws = new WebSocket(`${this.url}?userId=${this.userId}`, [], { perMessageDeflate: true });
    this.ws.binaryType = 'arraybuffer'; // 确保接收 ArrayBuffer

    this.ws.onopen = () => {
      console.log('WebSocket 已连接');
      this.status = true;
      this.startHeartbeat();
      this.processMessageQueue();
      this.dispatch('open');
    };

    this.ws.onmessage = async (event) => {
      const data = event.data instanceof Blob ? await event.data.arrayBuffer() : event.data;
      if (data instanceof ArrayBuffer && this.isMediaPacket(data)) {
        this.dispatchMediaPacket(data);
        return;
      }
      if (this.messageQueue.length >= this.maxQueueSize) {
        console.warn('WebSocket控制消息队列已满，丢弃最旧消息');
        this.messageQueue.shift();
      }
      this.messageQueue.push(data);
      this.processMessageQueue();
    };

    this.ws.onclose = () => {
      console.log('WebSocket 断开');
      this.status = false;
      this.stopHeartbeat();
      this.dispatch('close');
      if (!this.isManualClose) {
        this.reconnect();
      }
    };

    this.ws.onerror = (err) => {
      console.error('WebSocket 错误:', err);
    };
  }

  isMediaPacket(buffer) {
    if (buffer.byteLength < MEDIA_HEADER_SIZE) return false;
    const bytes = new Uint8Array(buffer, 0, MEDIA_MAGIC.length);
    return MEDIA_MAGIC.every((value, index) => bytes[index] === value);
  }

  dispatchMediaPacket(buffer) {
    try {
      const view = new DataView(buffer);
      const version = view.getUint8(4);
      const mediaType = view.getUint8(5);
      const timestamp = view.getUint32(8) * 0x100000000 + view.getUint32(12);
      const sequence = view.getUint32(16);
      const channelLength = view.getUint16(20);
      const payloadLength = view.getUint32(22);
      const payloadOffset = MEDIA_HEADER_SIZE + channelLength;
      if (version !== 1 || payloadOffset + payloadLength !== buffer.byteLength) {
        throw new Error('媒体数据包头无效');
      }
      const channel = new TextDecoder().decode(new Uint8Array(buffer, MEDIA_HEADER_SIZE, channelLength));
      const mimeType = MEDIA_MIME_TYPES[mediaType];
      if (!mimeType) {
        throw new Error(`不支持的媒体类型: ${mediaType}`);
      }
      this.dispatch(channel, {
        media: true,
        mimeType,
        sequence,
        timestamp,
        data: buffer.slice(payloadOffset, payloadOffset + payloadLength)
      });
    } catch (error) {
      console.error('WebSocket媒体包解析失败:', error);
    }
  }

  async processMessageQueue() {
    if (this.processingMessages || !this.ws) return;
    this.processingMessages = true;
    try {
      while (this.messageQueue.length > 0) {
        const data = this.messageQueue.shift();
        let message;
        if (typeof data === 'string') {
          message = JSON.parse(data);
        } else if (data instanceof ArrayBuffer) {
          const decompressedStream = new Blob([data])
            .stream()
            .pipeThrough(new DecompressionStream('gzip'));
          const decompressedData = await new Response(decompressedStream).arrayBuffer();
          message = JSON.parse(new TextDecoder().decode(decompressedData));
        } else {
          throw new Error(`不支持的WebSocket数据类型: ${typeof data}`);
        }
        if (message.channel) {
          this.dispatch(message.channel, message.payload);
        } else if (message.type) {
          this.dispatch(message.type, message.payload ?? message.content ?? message);
        }
      }
    } catch (err) {
      console.error('WebSocket消息解析失败:', err);
    } finally {
      this.processingMessages = false;
      if (this.messageQueue.length > 0) {
        queueMicrotask(() => this.processMessageQueue());
      }
    }
  }

  dispatch(eventName, payload) {
    const callbacks = this.events[eventName];
    if (callbacks) {
      callbacks.slice().forEach(callback => callback(payload));
    }
  }

  on(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
  }

  off(eventName, callback) {
    if (this.events[eventName]) {
      const index = this.events[eventName].indexOf(callback);
      if (index !== -1) {
        this.events[eventName].splice(index, 1);
      }
    }
  }

  send(payload) {
    if (this.ws && this.ws.readyState === 1) {
      this.ws.send(JSON.stringify(payload));
    } else {
      console.warn('WebSocket 未连接，消息发送失败');
    }
  }

  close() {
    this.isManualClose = true;
    this.status = false;
    this.stopHeartbeat();
    if (this.ws) {
      this.ws.close();
    }
  }

  reconnect() {
    clearTimeout(this.reconnectTimer);
    this.reconnectTimer = setTimeout(() => {
      console.log('尝试重新连接 WebSocket...');
      this.connect();
    }, 5000);
  }

  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      this.send({ type: 'heartbeat' });
    }, 30000);
  }

  stopHeartbeat() {
    clearInterval(this.heartbeatTimer);
  }

  status() {
    return this.status;
  }
}

export default {
  install(app, options) {
    const { url, userId } = options;
    const wsManager = new WebSocketManager(url, userId);
    wsManager.connect();
    app.config.globalProperties.$ws = wsManager;
    app.provide('ws', wsManager);
  }
};
