//  Copyright (c) 2024 Huawei Technologies Co., Ltd.
//  openUBMC is licensed under Mulan PSL v2.
//  You can use this software according to the terms and conditions of the Mulan PSL v2.
//  You may obtain a copy of Mulan PSL v2 at:
//        #  http://license.coscl.org.cn/MulanPSL2
//  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
//  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
//  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//  See the Mulan PSL v2 for more details.
import $http from '@/utils/http-service';
import { reqPath } from '@/api/reqPath';
import { CmdType } from '@/model/base-enum';
import { packed } from './packData';

export class Communication {
  public _ip;
  public _port;
  public _client;
  public _sock = null as any;
  public _heartTimer = null as any;
  public _securityWarning = 1;
  public _token;
  public _sessionId;
  public _host;
  constructor(client: any, ip: string, token: string, port: number, sessionId: string, host: number) {
    this._client = client;
    this._ip = ip;
    this._port = port;
    this._token = token,
    this._sessionId = sessionId;
    this._host = host;
    this._CreateConnection();
  }
  
  _CreateConnection() {
    this._sock = new WebSocket(`wss://${this._ip}:${this._port}/websocket/kvm`);
    // 监听浏览器页签关闭事件，发送断开链接请求
    window.onbeforeunload = () => {
      this._Send(packed.packDisconnect());
      localStorage.removeItem('kvmConnected');
    };
    this._sock.binaryType = 'arraybuffer';
    this._sock.onopen = (e: any) => {
      this._WSOpen(e);
    };
    this._sock.onclose = (e: any) => {
      this._WSClose(e);
    };
    this._sock.onerror = (e: any) => {
      this._WSError(e);
    };
    this._sock.onmessage = (e: any) => {
      this._WSMessage(e);
    };
  }

  // token字符串转义
  public getKvmToken() {
    const tokenLength = this._token?.length;
    const buffer = new Uint8Array(tokenLength);
    for (let i = 0; i < tokenLength; i++) {
      buffer[i] = this._token.charCodeAt(i);
    }
    return [...buffer];
  }

  _WSOpen(event: any) {
    this._securityWarning = 0;
    this._Send(packed.packConnect(this.getKvmToken(), this._host));
  }

  _WSClose(event: any) {
    clearInterval(this._heartTimer);
    localStorage.removeItem('kvmConnected');
    if (this._sock !== null) {
      this._sock.onopen = null;
      this._sock.onclose = null;
      this._sock.onerror = null;
      this._sock.onmessage = null;
      this._sock = null;
    }
    const handleDeleteKvmUser = (): void => {
      if (this._sessionId) {
        this.deleteKvmUser(this._sessionId);
      }
    };
    // code值1008表示KVM会话超时
    if (event?.code === 1008) {
      handleDeleteKvmUser();
      this._client.showMessage('REMOTE_ERR_TIMEOUT', 'disconnectDialog', 'HOME_PERFWARNING', 'warning', true);
    } else if (event?.code === 4001) {
      // code值4001表示KVM会话被强制踢出
      handleDeleteKvmUser();
      this._client.showMessage('REMOTE_FORCED_LOGOUT_KVM', 'logoutDialog', 'HOME_PERFWARNING', 'warning', true);
    } else {
      if (event.code !== 1015) {
        // 表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书)
        this._client.showMessage('REMOTE_ERR_NETWORK_INTERRUPT', 'networkInterruptDialog', 'COMMON_ERROR', 'error');
        handleDeleteKvmUser();
      }
    }
    this._client._toolbar._virtualMedia._Reset();
  }

  _WSError(event: any) {
    if (this._securityWarning === 1) {
      this._securityWarning = 0;
      this._ResolveSecurityWarning();
    }
  }

  // 注销kvm用户
  deleteKvmUser(id: string) {
    return new Promise((resolve, reject) => {
      $http
        .delete(`${reqPath.onlineUser.sessions}/${id}`)
        .then((res: any) => {
          resolve(res.data);
        })
        .catch((err: any) => {
          reject(err);
        });
    });
  }

  _WSMessage(event: any) {
    const data = new Uint8Array(event?.data);
    // 更新界面右下角接收数据(Recv)的值
    this._client._statusbar.updateRecive(data.length);
    const { bodyDataLength, cmdType, bodyData } = packed.parseData(data);
    switch (cmdType) {
      case CmdType.CONNECT_RSP_S:
        this.dealConnectRsp(bodyData);
        break;
      case CmdType.IMAGE_DATA_REQ_S:
        // 图像数据
        this.dealImageRsp(bodyDataLength, bodyData);
        break;
      case CmdType.GET_IMAGE_RESOLUTION_RSP_S:
        this.updateImageResolution(bodyData);
        break;
      case CmdType.POWER_CONTROL_RSP_S:
        this.showResponseTip(bodyData);
        break;
      case CmdType.GET_BOOT_OPTION_RSP_S:
        // 接收启动项的当前选中项
        this._client._toolbar.setBootOption(bodyData[0]);
        break;
      case CmdType.GET_BOOT_METHOD_RSP_S:
        // 接收启动项的生效方式
        this._client._toolbar.setBootMethod(bodyData[0]);
        break;
      case CmdType.SET_BOOT_OPTION_RSP_S:
        // 接收系统启动项设置成功与否状态
        this.showResponseTip(bodyData);
        break;
      case CmdType.GET_MOUSE_MODE_RSP_S:
        this.updateMouseMode(bodyData);
        break;
      case CmdType.KEYBOARD_STATUS_RSP_S:
        this.dealKeyboardLight(bodyData);
        break;
      case CmdType.VMM_ENABLE_RSP_S:
        this._client._toolbar._virtualMedia.parserVmmState(bodyData[0]);
        break;
      case CmdType.VMM_PORT_RSP_S:
        this.getVmmPort(bodyData);
        break;
      case CmdType.CUSTOM_DATA_GET_R:
        this.getCustom(bodyData);
        break;
      case CmdType.CUSTOM_DATA_SAVE_R:
        this.getErr(bodyData, 'save');
        break;
      case CmdType.CUSTOM_DATA_DEL_R:
        this.getErr(bodyData, 'delete');
        break;
      case CmdType.SCREEN_RECODING_END_REQ_F:
        this.getF(bodyData);
        break;
      default:
        break;
    }
  }

  dealConnectRsp(bodyData: Uint8Array) {
    if (bodyData[0] === 0) {
      // 连接成功后发送查询图像分辨率请求
      this._Send(packed.packGetImageResolution());
      // 发送强制I帧请求,连接成功后立即有完整图像
      this._Send(packed.packForceIFrame());
      // 发送鼠标初始状态请求
      this._Send(packed.packGetMouseMode());
      // 发送键盘初始化状态
      this._Send(packed.packInitKeyBoard());
      // 发送查询启动项选中项请求
      this._Send(packed.packGetBootOption());
      this._Send(packed.packGetBootMethod());
      // 发送查询自定义按键
      this._Send(packed.packGetCustom());
      this._Send(packed.packGetCurActiveHosts());
      this._Send(packed.packGetActiveHosts(this._host));
      localStorage.setItem('kvmConnected', JSON.stringify(true));
    }
  }

  dealImageRsp(bodyDataLength: number, bodyData: Uint8Array) {
    const imageBody = packed.parseImageBody(bodyData);
    if (bodyDataLength === imageBody.imageLength + 10) {
      this._client._display.drawImage(imageBody);
    }
    // 接收到图像信息时发送一次心跳
    this._Send(packed.packHeartBeat());
  }

  updateImageResolution(bodyData: Uint8Array) {
    this._client._toolbar._slider.value = bodyData[0];
  }

  updateMouseMode(bodyData: Uint8Array) {
    this._client._toolbar.setMouseAcceleration(bodyData[0]);
  }

  dealKeyboardLight(bodyData: Uint8Array) {
    this._client._toolbar.setKeyboardLight(bodyData[0]);
  }

  getVmmPort(data: Uint8Array) {
    const port = (data[0] << 8) + data[1];
    this._client._toolbar._virtualMedia.parserVmmPort(port);
  }

  getCustom(data: Uint8Array): void {
    this._client._toolbar._CustomData(data);
  }

  getErr(data: Uint8Array, type: any): void {
    this._client._toolbar._CustomErrData(data, type);
  }

  /** 主机激活状态的更新处理
    比较当前激活的主机ID和当前会话的主机ID
    如果不一致，说明当前主机ID未激活，显示预置图像，未激活的tag
    如果一致，正常显示，已激活的tag
    */
  getF(data: Uint8Array): void {
    const hostId = data[0];
    if (hostId !== this._host) {
      this._client._toolbar.setHostInfo('idle', this._host);
    } else {
      this._client._toolbar.setHostInfo('active', this._host);
    }
  }

  public showResponseTip(bodyData: Uint8Array) {
    let contentInfo = '';
    let id = 'ResponseSuccessTip';
    let title = '';
    let type = '';
    switch (bodyData[0]) {
      case 0:
        contentInfo = 'COMMON_SUCCESS';
        break;
      case 1:
        contentInfo = 'COMMON_FAILED';
        type = 'warning';
        break;
      case 2:
        contentInfo = 'HOME_NO_ACCESS';
        type = 'error';
        break;
      default:
        break;
    }

    this._client.showMessage(contentInfo, id, title, type);
  }

  _ResolveSecurityWarning() {
    const self = this;
    let interval = null as any;
    let times = 0;

    function receiver(event: any) {
      if (event.data === 'Certificate OK.') {
        clearInterval(interval);
        window.removeEventListener('message', receiver);
        self._CreateConnection();
      }
    }
    const targetOrigin = `https://${this._ip}:${this._port}`;
    const popupWin = window.open(targetOrigin, '_blank');
    if (popupWin) {
      popupWin.opener = null;
    }
    window.addEventListener('message', receiver);

    interval = setInterval(() => {
      popupWin?.postMessage('hello', targetOrigin);
      if (times++ > 150) {
        clearInterval(interval);
        window.removeEventListener('message', receiver);
        this._client.showMessage('REMOTE_ERR_VERIFY_TIMEOUT', 'verifyTimeoutDialog');
      }
    }, 200);
  }

  _Send(data: any) {
    if (this._sock != null && Number(this._sock.readyState) === 1) {
      // 更新界面右下角发送数据(Send)的值
      this._client._statusbar.updateSend(data?.length);
      this._sock.send(data?.buffer);
    }
  }
}
