import { getRandomString } from 'billd-utils';

import { LiveLineEnum, MediaTypeEnum } from '@/interface';
import { AppRootState, useAppStore } from '@/store/app';
import { useNetworkStore } from '@/store/network';
import { WsCandidateType, WsMsgTypeEnum } from '@/types/websocket';

/** 设置分辨率 */
export async function handleResolutionRatio(data: {
  frameRate: number;
  height: number;
  stream: MediaStream;
}): Promise<number> {
  const { frameRate, height, stream } = data;
  const queue: Promise<any>[] = [];
  console.log('开始设置分辨率', height);
  stream.getTracks().forEach((track) => {
    if (track.kind === 'video') {
      queue.push(
        track.applyConstraints({
          height: { ideal: height },
          frameRate: { ideal: frameRate },
        })
      );
    }
  });
  try {
    await Promise.all(queue);
    console.log('设置分辨率成功');
    return 1;
  } catch (error) {
    console.error('设置分辨率失败', height, error);
    return 0;
  }
}
/** 设置帧率 */
export async function handleMaxFramerate(data: {
  frameRate: number;
  height: number;
  stream: MediaStream;
}): Promise<number> {
  const { frameRate, height, stream } = data;
  const queue: Promise<any>[] = [];
  console.log('开始设置帧率', frameRate);
  stream.getTracks().forEach((track) => {
    if (track.kind === 'video') {
      console.log('开始设置帧率---', frameRate, track.id);
      queue.push(
        track.applyConstraints({
          height: { ideal: height },
          frameRate: { ideal: frameRate },
        })
      );
    }
  });
  try {
    await Promise.all(queue);
    console.log('设置帧率成功');
    return 1;
  } catch (error) {
    console.error('设置帧率失败', frameRate, error);
    return 0;
  }
}

export class WebRTCClass {
  isAnchor = false;
  roomId = '-1';
  sender = '';
  receiver = '';

  videoEl: HTMLVideoElement;

  peerConnection: RTCPeerConnection | null = null;

  /** 最大码率 */
  maxBitrate = -1;
  /** 最大帧率 */
  maxFramerate = -1;
  /** 分辨率 */
  resolutionRatio = -1;

  localStream?: MediaStream;

  isSRS: boolean;

  constructor(data: {
    isAnchor: boolean;
    roomId: string;
    videoEl: HTMLVideoElement;
    maxBitrate?: number;
    maxFramerate?: number;
    resolutionRatio?: number;
    isSRS: boolean;
    sender: string;
    receiver: string;
    localStream?: MediaStream;
  }) {
    this.isAnchor = data.isAnchor;
    this.roomId = data.roomId;
    this.videoEl = data.videoEl;
    // document.body.appendChild(this.videoEl);
    this.sender = data.sender;
    this.receiver = data.receiver;
    this.localStream = data.localStream;
    if (data.maxBitrate) {
      this.maxBitrate = data.maxBitrate;
    }
    if (data.resolutionRatio) {
      this.resolutionRatio = data.resolutionRatio;
    }
    if (data.maxFramerate) {
      this.maxFramerate = data.maxFramerate;
    }
    this.isSRS = data.isSRS;
    console.warn('new webrtc参数:', data);
    this.createPeerConnection();
  }

  prettierLog = (msg: string, type?: 'log' | 'warn' | 'error', ...args) => {
    console[type || 'log'](
      `${new Date().toLocaleString()}，${this.roomId}，${msg}`,
      ...args
    );
  };

  addTrack = (stream: MediaStream, isCb?: boolean) => {
    console.log('开始addTrack,是否是pc的track回调', isCb);
    console.log('收到新track', stream);
    console.log('收到新track的视频轨', stream.getVideoTracks());
    console.log('收到新track的音频轨', stream.getAudioTracks());
    console.log('原本旧track的视频轨', this.localStream?.getVideoTracks());
    console.log('原本旧track的音频轨', this.localStream?.getAudioTracks());

    const appStore = useAppStore();
    if (isCb) {
      stream.onremovetrack = (event) => {
        console.log('onremovetrack事件', event);
        const res = appStore.allTrack.filter((info) => {
          if (info.track?.id === event.track.id) {
            return false;
          }
          return true;
        });
        appStore.setAllTrack(res);
      };
    }

    const addTrack: AppRootState['allTrack'] = [];

    this.localStream?.getVideoTracks().forEach((track) => {
      if (!appStore.allTrack.find((info) => info.track?.id === track.id)) {
        addTrack.push({
          openEye: true,
          id: getRandomString(8),
          track,
          stream,
          audio: 2,
          video: 1,
          type: MediaTypeEnum.screen,
          mediaName: '',
          streamid: stream.id,
          trackid: track.id,
          scaleInfo: {},
        });
      }
    });
    this.localStream?.getAudioTracks().forEach((track) => {
      if (!appStore.allTrack.find((info) => info.track?.id === track.id)) {
        addTrack.push({
          openEye: true,
          id: getRandomString(8),
          track,
          stream,
          audio: 1,
          video: 2,
          type: MediaTypeEnum.microphone,
          mediaName: '',
          streamid: stream.id,
          trackid: track.id,
          scaleInfo: {},
        });
      }
    });
    stream.getVideoTracks().forEach((track) => {
      if (!appStore.allTrack.find((info) => info.track?.id === track.id)) {
        addTrack.push({
          openEye: true,
          id: getRandomString(8),
          track,
          stream,
          audio: 2,
          video: 1,
          type: MediaTypeEnum.screen,
          mediaName: '',
          streamid: stream.id,
          trackid: track.id,
          scaleInfo: {},
        });
      }
    });
    stream.getAudioTracks().forEach((track) => {
      if (!appStore.allTrack.find((info) => info.track?.id === track.id)) {
        addTrack.push({
          openEye: true,
          id: getRandomString(8),
          track,
          stream,
          audio: 1,
          video: 2,
          type: MediaTypeEnum.microphone,
          mediaName: '',
          streamid: stream.id,
          trackid: track.id,
          scaleInfo: {},
        });
      }
    });
    // if (addTrack.length) {
    //   appStore.setAllTrack([...appStore.allTrack, ...addTrack]);
    // }
    this.localStream = stream;
    appStore.pkStream = stream;
  };

  /** 设置分辨率 */
  setResolutionRatio = async (height: number) => {
    if (this.localStream) {
      const res = await handleResolutionRatio({
        frameRate: this.maxFramerate,
        stream: this.localStream,
        height,
      });
      console.log(res, '设置分辨率');
      return res;
    }
  };

  /** 设置最大帧率 */
  setMaxFramerate = async (maxFramerate: number) => {
    console.log(this.localStream, maxFramerate, '设置最大帧率111');
    if (this.localStream) {
      const res = await handleMaxFramerate({
        frameRate: maxFramerate,
        stream: this.localStream,
        height: this.resolutionRatio,
      });
      console.log(res, '设置最大帧率');
      return res;
    }
    // return new Promise<number>((resolve) => {
    // this.peerConnection?.getSenders().forEach((sender) => {
    //   if (sender.track?.kind === 'video') {
    //     const parameters = { ...sender.getParameters() };
    //     if (parameters.encodings[0]) {
    //       if (parameters.encodings[0].maxFramerate === maxFramerate) {
    //         console.log('最大帧率不变，不设置');
    //         resolve(1);
    //         return;
    //       }
    //       parameters.encodings[0].maxFramerate = maxFramerate;
    //       sender
    //         .setParameters(parameters)
    //         .then(() => {
    //           console.log('设置最大帧率成功', maxFramerate);
    //           this.maxFramerate = maxFramerate;
    //           resolve(1);
    //         })
    //         .catch((error) => {
    //           console.error('设置最大帧率失败', maxFramerate, error);
    //           resolve(0);
    //         });
    //     }
    //   }
    // });
    // });
  };

  /** 设置最大码率 */
  setMaxBitrate = (maxBitrate: number) => {
    console.log('开始设置最大码率', maxBitrate);
    return new Promise<number>((resolve) => {
      this.peerConnection?.getSenders().forEach((sender) => {
        if (sender.track?.kind === 'video') {
          const parameters = { ...sender.getParameters() };
          if (parameters.encodings[0]) {
            const val = 1000 * maxBitrate;
            if (parameters.encodings[0].maxBitrate === val) {
              console.log('最大码率不变，不设置');
              resolve(1);
              return;
            }
            parameters.encodings[0].maxBitrate = val;
            sender
              .setParameters(parameters)
              .then(() => {
                console.log('设置最大码率成功', maxBitrate);
                this.maxBitrate = val;
                resolve(1);
              })
              .catch((error) => {
                console.error('设置最大码率失败', maxBitrate, error);
                resolve(0);
              });
          }
        }
      });
    });
  };

  // 创建offer
  createOffer = async () => {
    if (!this.peerConnection) return;
    this.prettierLog('createOffer开始', 'warn');
    try {
      const sdp = await this.peerConnection.createOffer();
      this.prettierLog('createOffer成功', 'warn', sdp);
      return sdp;
    } catch (error) {
      this.prettierLog('createOffer失败', 'error');
      console.log(error);
    }
  };

  addIceCandidate = async (candidate: RTCIceCandidateInit) => {
    try {
      await this.peerConnection?.addIceCandidate(candidate);
      console.log('addIceCandidate成功');
    } catch (error) {
      console.error('addIceCandidate错误');
      console.log(error);
    }
  };

  // 创建answer
  createAnswer = async () => {
    if (!this.peerConnection) return;
    this.prettierLog('createAnswer开始', 'warn');
    try {
      const sdp = await this.peerConnection.createAnswer();
      this.prettierLog('createAnswer成功', 'warn', sdp);
      return sdp;
    } catch (error) {
      this.prettierLog('createAnswer失败', 'error');
      console.log(error);
    }
  };

  // 设置本地描述
  setLocalDescription = async (sdp: RTCLocalSessionDescriptionInit) => {
    if (!this.peerConnection) return;
    this.prettierLog('setLocalDescription开始', 'warn');
    try {
      await this.peerConnection.setLocalDescription(sdp);
      this.prettierLog('setLocalDescription成功', 'warn', sdp);
    } catch (error) {
      this.prettierLog('setLocalDescription失败', 'error');
      console.error('setLocalDescription', sdp);
      console.error(error);
    }
  };

  // 设置远端描述
  setRemoteDescription = async (sdp: RTCSessionDescriptionInit) => {
    if (!this.peerConnection) return;
    this.prettierLog(`setRemoteDescription开始`, 'warn');
    try {
      await this.peerConnection.setRemoteDescription(sdp);
      this.prettierLog('setRemoteDescription成功', 'warn', sdp);
    } catch (error) {
      this.prettierLog('setRemoteDescription失败', 'error');
      console.error('setRemoteDescription', sdp);
      console.error(error);
    }
  };

  handleStreamEvent = () => {
    if (!this.peerConnection) return;
    // 废弃：https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream
    console.warn(`${this.roomId}，开始监听pc的addstream`);
    this.peerConnection.addEventListener('addstream', () => {
      // console.warn(`${this.roomId}，pc收到addstream事件`, event);
      // console.log('addstream事件的stream', event.stream);
      // console.log('addstream事件的视频轨', event.stream.getVideoTracks());
      // console.log('addstream事件的音频轨', event.stream.getAudioTracks());
    });

    console.warn(`${this.roomId}，开始监听pc的track`);
    this.peerConnection.addEventListener('track', (event) => {
      console.warn(`${this.roomId}，pc收到track事件`, event);
      console.log('track事件的stream', event.streams[0]);
      console.log('track事件的视频轨', event.streams[0].getVideoTracks());
      console.log('track事件的音频轨', event.streams[0].getAudioTracks());
      this.addTrack(event.streams[0], true);
      this.videoEl.srcObject = event.streams[0];
    });
  };

  handleConnectionEvent = () => {
    if (!this.peerConnection) return;
    const appStore = useAppStore();

    console.warn(`${this.roomId}，开始监听pc的icecandidate`);
    // icecandidate
    this.peerConnection.addEventListener('icecandidate', (event) => {
      this.prettierLog('pc收到icecandidate', 'warn');
      if (event.candidate) {
        const networkStore = useNetworkStore();
        console.log('准备发送candidate', event.candidate.candidate);
        const roomId = this.roomId.split('___')[1];
        console.log({
          roomId,
          sender: this.sender,
          receiver: this.receiver,
        });
        networkStore.wsMap.get(roomId)?.send<WsCandidateType['data']>({
          requestId: getRandomString(8),
          msgType: this.isSRS
            ? WsMsgTypeEnum.srsCandidate
            : WsMsgTypeEnum.nativeWebRtcCandidate,
          data: {
            candidate: event.candidate,
            sender: this.isAnchor ? this.sender : this.receiver,
            receiver: this.isAnchor ? this.receiver : this.sender,
            live_room_id: Number(roomId),
          },
        });
      } else {
        console.log('没有候选者了');
      }
    });

    console.warn(`${this.roomId}，开始监听pc的iceconnectionstatechange`);
    // iceconnectionstatechange
    this.peerConnection.addEventListener(
      'iceconnectionstatechange',
      (event: any) => {
        // https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection/connectionState
        const iceConnectionState = event.currentTarget.iceConnectionState;
        console.log(
          this.roomId,
          'pc收到iceconnectionstatechange',
          // eslint-disable-next-line
          `iceConnectionState:${iceConnectionState}`,
          event
        );
        if (iceConnectionState === 'connected') {
          // ICE 代理至少对每个候选发现了一个可用的连接，此时仍然会继续测试远程候选以便发现更优的连接。同时可能在继续收集候选。
          console.warn(this.roomId, 'iceConnectionState:connected', event);
        }
        if (iceConnectionState === 'completed') {
          // ICE 代理已经发现了可用的连接，不再测试远程候选。
          console.warn(this.roomId, 'iceConnectionState:completed', event);
        }
        if (iceConnectionState === 'failed') {
          // ICE 候选测试了所有远程候选没有发现匹配的候选。也可能有些候选中发现了一些可用连接。
          console.error(this.roomId, 'iceConnectionState:failed', event);
        }
        if (iceConnectionState === 'disconnected') {
          // 测试不再活跃，这可能是一个暂时的状态，可以自我恢复。
          console.error(this.roomId, 'iceConnectionState:disconnected', event);
        }
        if (iceConnectionState === 'closed') {
          // ICE 代理关闭，不再应答任何请求。
          console.error(this.roomId, 'iceConnectionState:closed', event);
        }
      }
    );

    console.warn(`${this.roomId}，开始监听pc的connectionstatechange`);
    // connectionstatechange
    this.peerConnection.addEventListener(
      'connectionstatechange',
      (event: any) => {
        const connectionState = event.currentTarget.connectionState;
        console.log(
          this.roomId,
          'pc收到connectionstatechange',
          // eslint-disable-next-line
          `connectionState:${connectionState}`,
          event
        );
        if (connectionState === 'connected') {
          // 表示每一个 ICE 连接要么正在使用（connected 或 completed 状态），要么已被关闭（closed 状态）；并且，至少有一个连接处于 connected 或 completed 状态。
          console.warn(this.roomId, 'connectionState:connected');
          appStore.setLiveLine(LiveLineEnum.rtc);
          if (this.maxBitrate !== -1) {
            this.setMaxBitrate(this.maxBitrate);
          }
          if (this.maxFramerate !== -1) {
            this.setMaxFramerate(this.maxFramerate);
          }
          if (this.resolutionRatio !== -1) {
            this.setResolutionRatio(this.resolutionRatio);
          }
          console.log(
            this.maxBitrate,
            this.maxFramerate,
            this.resolutionRatio,
            '配置'
          );
        }
        if (connectionState === 'disconnected') {
          // 表示至少有一个 ICE 连接处于 disconnected 状态，并且没有连接处于 failed、connecting 或 checking 状态。
          console.error(this.roomId, 'connectionState:disconnected');
        }
        if (connectionState === 'closed') {
          // 表示 RTCPeerConnection 已关闭。
          console.error(this.roomId, 'connectionState:closed');
        }
        if (connectionState === 'failed') {
          // 表示至少有一个 ICE 连接处于 failed 的状态。
          console.error(this.roomId, 'connectionState:failed');
        }
      }
    );
    // negotiationneeded
    // this.peerConnection.addEventListener('negotiationneeded', (event: any) => {
    //   console.log(this.roomId, 'pc收到negotiationneeded', event);
    // });
  };

  // 创建对等连接
  createPeerConnection = () => {
    if (!window.RTCPeerConnection) {
      console.error('当前环境不支持RTCPeerConnection！');
      alert('当前环境不支持RTCPeerConnection！');
      return;
    }
    if (!this.peerConnection) {
      const iceServers = this.isSRS
        ? []
        : [
            // {
            //   urls: 'stun:stun.l.google.com:19302',
            // },
            {
              urls: 'turn:live.hsslive.cn:3478',
              username: 'hss',
              credential: '123456',
            },
          ];
      this.peerConnection = new RTCPeerConnection({
        iceServers,
      });
      this.handleStreamEvent();
      this.handleConnectionEvent();
      this.update();
    }
  };

  // 手动关闭webrtc连接
  close = () => {
    this.prettierLog('手动关闭webrtc连接', 'warn');
    this.peerConnection?.getSenders().forEach((sender) => {
      this.peerConnection?.removeTrack(sender);
    });
    this.peerConnection?.close();
    this.peerConnection = null;
  };

  // 更新store
  update = () => {
    const networkStore = useNetworkStore();
    networkStore.updateRtcMap(this.roomId, this);
  };
}
