/*
 * @Author: 赵伟
 * @Date: 2024-05-16 08:47:46
 * @Description: 日志组件
 */

import { ExperimentStatus } from '@/enums';
import { useStateRef } from '@/hooks/useStateRef';
import { getExperimentPodsLog } from '@/services/experiment/index.js';
import { DoubleRightOutlined, DownOutlined, UpOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import classNames from 'classnames';
import dayjs from 'dayjs';
import { useEffect, useRef, useState } from 'react';
import { ExperimentLog } from '../LogList';
import styles from './index.less';

export type LogGroupProps = ExperimentLog & {
  status?: ExperimentStatus; // 实验状态
};

type Log = {
  start_time: string; // 日志开始时间
  log_content: string; // 日志内容
  pod_name: string; // pod名称
};

function LogGroup({
  log_type = 'normal',
  pod_name = '',
  log_content = '',
  start_time,
  status,
}: LogGroupProps) {
  const [collapse, setCollapse] = useState(true);
  const [logList, setLogList] = useState<Log[]>([]);
  const [completed, setCompleted] = useState(false);
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [_isMouseDown, setIsMouseDown, isMouseDownRef] = useStateRef(false);
  const socketRef = useRef<WebSocket | undefined>(undefined);
  const retryRef = useRef(2); // 等待 2 秒，重试 3 次
  const logElementRef = useRef<HTMLDivElement | null>(null);
  // 如果是【运行中】状态，设置 hasRun 为 true，【运行中】或者从【运行中】切换到别的状态时，不显示【更多】按钮
  const [hasRun, setHasRun] = useState(false);
  if (status === ExperimentStatus.Running && !hasRun) {
    setHasRun(true);
  }

  // 进入页面时，滚动到底部
  useEffect(() => {
    scrollToBottom(false);
  }, []);

  useEffect(() => {
    // 建立 socket 连接
    const setupSockect = () => {
      let { host } = location;
      if (process.env.NODE_ENV === 'development') {
        host = '172.20.32.235:31213';
      }
      const socket = new WebSocket(
        `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`,
      );

      socket.addEventListener('open', () => {
        console.log('WebSocket is open now.');
      });

      socket.addEventListener('close', (event) => {
        console.log('WebSocket is closed:', event);
        // 有时候会出现连接失败，重试 3 次
        if (event.code !== 1000 && retryRef.current > 0) {
          retryRef.current -= 1;
          setTimeout(() => {
            setupSockect();
          }, 2 * 1000);
        }
      });

      socket.addEventListener('error', (event) => {
        console.error('WebSocket error observed:', event);
      });

      socket.addEventListener('message', (event) => {
        // console.log('message received.', event);
        if (!event.data) {
          return;
        }
        try {
          const data = JSON.parse(event.data);
          const streams = data.streams;
          if (!streams || !Array.isArray(streams)) {
            return;
          }
          let startTime = start_time;
          const logContent = streams.reduce((result, item) => {
            const values = item.values;
            return (
              result +
              values.reduce((prev: string, cur: [string, string]) => {
                const [time, value] = cur;
                startTime = time;
                const str = `[${dayjs(Number(time) / 1.0e6).format(
                  'YYYY-MM-DD HH:mm:ss',
                )}] ${value}`;
                return prev + str;
              }, '')
            );
          }, '');
          const logDetail: Log = {
            start_time: startTime!,
            log_content: logContent,
            pod_name: pod_name,
          };
          setLogList((oldList) => oldList.concat(logDetail));
          if (!isMouseDownRef.current && logContent) {
            setTimeout(() => {
              scrollToBottom();
            }, 100);
          }
        } catch (error) {
          console.error('JSON parse error: ', error);
        }
      });

      socketRef.current = socket;
    };

    // 关闭 socket
    const closeSocket = () => {
      if (socketRef.current) {
        socketRef.current.close(1000, 'completed');
        socketRef.current = undefined;
      }
    };

    if (status === ExperimentStatus.Running) {
      setupSockect();
    }

    return () => {
      closeSocket();
    };
  }, [status, start_time, pod_name, isMouseDownRef]);

  // 鼠标拖到中不滚动到底部
  useEffect(() => {
    const mouseDown = () => {
      setIsMouseDown(true);
    };
    const mouseUp = () => {
      setIsMouseDown(false);
    };
    document.addEventListener('mousedown', mouseDown);
    document.addEventListener('mouseup', mouseUp);
    return () => {
      document.removeEventListener('mousedown', mouseDown);
      document.removeEventListener('mouseup', mouseUp);
    };
  }, [setIsMouseDown]);

  // 请求日志
  const requestExperimentPodsLog = async () => {
    const last = logList[logList.length - 1];
    const startTime = last ? last.start_time : start_time;
    const params = {
      pod_name,
      start_time: startTime,
    };
    const res = await getExperimentPodsLog(params);
    const { log_detail } = res.data || {};
    if (log_detail) {
      setLogList((oldList) => oldList.concat(log_detail));

      if (!isMouseDownRef.current && log_detail.log_content) {
        setTimeout(() => {
          scrollToBottom();
        }, 100);
      }
    }

    // 判断是否日志是否加载完成
    if (!log_detail?.log_content) {
      setCompleted(true);
    }
  };

  // 处理折叠
  const handleCollapse = async () => {
    if (!collapse) {
      setCollapse(true);
      return;
    }

    if (logList.length === 0) {
      try {
        await requestExperimentPodsLog();
        setCollapse(false);
      } catch (error) {
        return Promise.reject(error);
      }
    } else {
      setCollapse(false);
    }
  };

  // 加载更多
  const loadMore = () => {
    requestExperimentPodsLog();
  };

  // 滚动到底部
  const scrollToBottom = (smooth: boolean = true) => {
    // const element = document.getElementById(listId);
    // if (element) {
    //   const optons: ScrollToOptions = {
    //     top: element.scrollHeight,
    //     behavior: smooth ? 'smooth' : 'instant',
    //   };
    //   element.scrollTo(optons);
    // }
    logElementRef?.current?.scrollIntoView({
      block: 'end',
      behavior: smooth ? 'smooth' : 'instant',
    });
  };

  const showLog = (log_type === 'resource' && !collapse) || log_type === 'normal';
  const logText = log_content + logList.map((v) => v.log_content).join('');
  const showMoreBtn = !hasRun && !completed && showLog && logText !== '';
  return (
    <div className={styles['log-group']} ref={logElementRef}>
      {log_type === 'resource' && (
        <div className={styles['log-group__pod']} onClick={handleCollapse}>
          <div className={styles['log-group__pod__name']}>{pod_name}</div>
          {collapse ? <DownOutlined /> : <UpOutlined />}
        </div>
      )}
      {showLog && (
        <div
          className={classNames(styles['log-group__detail'], {
            [styles['log-group__detail--empty']]: !logText,
          })}
        >
          {logText ? logText : '暂无日志'}
        </div>
      )}
      <div className={styles['log-group__more-button']}>
        {showMoreBtn && (
          <Button type="text" style={{ color: 'white' }} onClick={loadMore}>
            更多
            <DoubleRightOutlined rotate={90} />
          </Button>
        )}
      </div>
    </div>
  );
}

export default LogGroup;
