import React, { useRef, useEffect, useState } from 'react';
import { Base64 } from 'js-base64';

import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
import mediator from './mediator';
import ResizeObserver from 'resize-observer-polyfill';

function getColsAndRows(width, height, term) {
  let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
  let h = term._core._renderService.dimensions.actualCellHeight || 18;
  const rows = Math.floor(height / h);
  const cols = Math.floor(width / w);
  return [cols, rows];
}

function onLayout(term, el) {
  const ro = new ResizeObserver(entries => {
    console.log(entries);
    for (let entry of entries) {
      if (entry.target.offsetHeight > 0 || entry.target.offsetWidth > 0) {
        const [cols, rows] = getColsAndRows(
          entry.target.offsetWidth,
          entry.target.offsetHeight,
          term,
        );
        term.resize(cols, rows);
        mediator.publish('ssh-xterm-resize', {
          columns: cols,
          rows: rows,
          width: entry.target.offsetWidth,
          height: entry.target.offsetHeight,
        });
      }
    }
  });
  ro.observe(el);
  return ro;
}

const TimeTicket = 30000;

//建立 websockt 来交互
//根据容器大小计算行数和列数并做到自适应
//socket 与 term 需要分开初始化 因为socket 可能重置连接
//mediator 监听消息，如果和id匹配，则建立连接，重置，或关闭连接

export default ({ sshConfigData, sid }) => {
  const [term, setTerm] = useState(null);

  const { ws_url, password, port, secret } = sshConfigData;
  const el = useRef();
  const socket = useRef();
  const isFirstConnected = useRef(false);

  //term init
  useEffect(() => {
    if (el.current && ws_url) {
      const term = new Terminal({ fontSize: 16, rendererType: 'dom' });
      term.open(el.current);

      term.onData(data => {
        if (socket.current) {
          if (socket.current.readyState === 1) {
            socket.current.send(JSON.stringify({ tp: 'client', data: data }));
            mediator.publish('on-operating-ssh'); //有操作则自动延时
          } else {
            //断开连接后重连
            // socket.current = null
            // mediator.publish('create-socket', sid)
          }
        }
      });
      term.write('Connecting...');
      setTerm(term);
      const ro = onLayout(term, el.current);
      return () => {
        term.dispose();
        ro.unobserve(el.current);
      };
    }
  }, [ws_url, el.current]);

  useEffect(() => {
    if (term && ws_url) {
      function createSocket() {
        const socketInstance = new WebSocket(ws_url);
        socket.current = socketInstance;

        socketInstance.onopen = () => {
          let container = term.element.parentElement;
          if (container) {
            let width = container.offsetWidth;
            let height = container.offsetHeight;
            console.log('init', {
              tp: 'init',
              data: {
                ...sshConfigData,
                secret: secret,
                width,
                height,
                rows: term.rows,
                columns: term.cols,
              },
            });
            socketInstance.send(
              JSON.stringify({
                tp: 'init',
                data: {
                  ...sshConfigData,
                  secret: secret,
                  width,
                  height,
                  rows: term.rows,
                  columns: term.cols,
                },
              }),
            );
          }
          term.focus();
        };
        socketInstance.onerror = error => {
          console.log(
            '------in socket error----',
            error,
            socketInstance,
            ws_url,
          );
          //连接报错后，重新请求资源
          // mediator.publish('on-recreate-socket')
        };
        socketInstance.onmessage = event => {
          if (!isFirstConnected.current) {
            term.write('\r');
            // term.focus()
            setTimeout(() => {
              // term.clear();
            }, 1000);
          }
          isFirstConnected.current = true;

          const data = Base64.decode(event.data.toString());
          let w = term._core._renderService.dimensions.actualCellWidth || 9.5;

          term.write(data);
        };

        socketInstance.onclose = evt => {
          if (tid) {
            clearInterval(tid);
          }
          term.write('\r\nconnection closed');
        };
      }

      const tid = setInterval(() => {
        if (socket.current) {
          socket.current.send(JSON.stringify({ tp: 'h' }));
        }
      }, TimeTicket);

      const unSubCreate = mediator.subscribe('create-socket', id => {
        if (sid === id) {
          if (socket.current && socket.current.readyState === 1) {
            term.focus();
          } else {
            createSocket();
          }
          term.focus();
        }
      });

      const unSubClose = mediator.subscribe('close-socket', id => {
        if (sid === id) {
          if (socket.current) {
            socket.current.close();
            isFirstConnected.current = false;
            term.clear();
          }
          socket.current = null;
        }
      });

      const unSubResize = mediator.subscribe('ssh-xterm-resize', option => {
        if (socket.current && socket.current.readyState === 1) {
          socket.current.send(
            JSON.stringify({ tp: 'resize', data: { ...option } }),
          );
        }
      });

      const unSubAddTime = mediator.subscribe('ssh-add-connect-time', () => {
        if (socket.current && socket.current.readyState === 1) {
          socket.current.send(JSON.stringify({ tp: 'overtime' }));
        }
      });

      return () => {
        unSubClose();
        unSubCreate();
        unSubResize();
        unSubAddTime();
        if (socket.current) {
          socket.current.close();
          isFirstConnected.current = false;
        }
      };
    }
  }, [term, ws_url, port]);

  return (
    <div ref={el} className="xterm-panel" style={{height:"100%"}}>
      {!ws_url ? <p style={{ color: '#fff' }}>正在连接命令行服务...</p> : null}
    </div>
  );
};