/* eslint-disable no-lonely-if */
import { YUWQUEVISIBLE_AUDIO } from '../../../../../utils/config';
import bus from '../../../../../../../utils/bus';
import {
  debounce,
  formatHMSHover,
  getSplitPercent,
  isMac,
} from '../../../../../../../utils/misc';
import { Tooltip, TYIcon } from '@tingwujs/design';
import { getFlexibleTime } from '@tingwujs/common';
import { Popover, Slider, Switch } from 'antd';
import React, {
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import AudioWave from '../AudioWave';
import {
  ControlParams,
  MarkPointParams,
  MarkSegParams,
  MarkSegResult,
  TimeTooltipContent,
} from '../control';
import {
  AudioPlayerControlBar,
  AudioWaveWrap,
  Bar,
  LeftControlBar,
  MarkWrap,
  PlayIconWrap,
  PointBox,
  RightControlBar,
  SliderWrap,
  SpeedSelect,
  VolumeContent,
} from './styled';
import TimeTooltip from './TimeTooltip';

export const POINTTIMEINFOVISIBLE = 'tingwu2_pointTime_info_visible';
export const CHANGESEEK = 'tingwu2_change_seek';

let yuqueVisible = true;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
let contentWidth = 0;

const AudioController: React.ForwardRefRenderFunction<
  unknown,
  ControlParams & { audio: any }
> = (props: ControlParams & { audio: any }, ref) => {
  const {
    audio,
    audioRateList = [2, 1.5, 1.25, 1, 0.75],
    markSegmentList: defaultMarkSegmentList = [],
    markPointList: defalutMarkPointList = [],
    spectrum = [],
  } = props;

  const [loading, setLoading] = useState(true); // 加载状态
  const [speedTipsVisible, setSpeedTipsVisible] = useState(false); // 倍速框

  const [paused, setPaused] = useState(true); // 播放状态
  const [volume, setVolume] = useState(100); // 音量
  const [muted, SetMuted] = useState(false); // 音量
  const [speed, setSpeed] = useState(1); // 倍速
  const [duration, setDuration] = useState(0); // 总时长
  const [currentTime, setCurrentTime] = useState(0); // 当前时间
  const [skipBlank, setSkipBlank] = useState(false); // 是否跳过空白片段

  const [tips, setTips] = useState([]); // 打标

  const controlRef = useRef<HTMLDivElement>(null);
  const [current, setCurrent] = useState(0);
  const [wrapperWidth, setWrapperWidth] = useState(0);
  const [isDrag, setIsDrag] = useState(false);
  const [percent, setPercent] = useState(0); // 已播放百分比
  const [markSegData, setMarkSegData] = useState<MarkSegResult[]>([]); // 章节速览片段
  const [mouseLoc, setMouseLoc] = useState(undefined); // 设置鼠标拖动滑块的位置
  const [hltMarkSegIndex, setHltMarkSegIndex] = useState<number>(-1);

  const [shortcutKey, setShortcutKey] = useState(false); // 快捷键开关
  const [markPointList, setMarkPointList] =
    useState<MarkPointParams[]>(defalutMarkPointList);
  const [markSegmentList, setMarkSegmentList] = useState<MarkSegParams[]>(
    defaultMarkSegmentList,
  );

  // 鼠标hover在进度条上时的进度信息框配置
  const [pointTimeBoxData, setPointTimeBoxData] = useState<
    TimeTooltipContent | {}
  >({});

  const [jumpTipsTime, setJumpTipsTime] = useState<string>();

  const proxyInstance = {
    paused,
    volume,
    muted,
    speed,
    currentTime,
    skipBlank,
    hltMarkSegIndex,
    shortcutKey,
    markPointList,
    markSegmentList,
    setPaused,
    setVolume,
    SetMuted,
    setSpeed,
    setCurrentTime,
    setSkipBlank,
    setHltMarkSegIndex,
    setShortcutKey,
    setMarkPointList,
    setMarkSegmentList,
    setJumpTipsTime,
  };

  useImperativeHandle(ref, () => proxyInstance);

  const timeupdateCb = (time: number) => {
    setCurrentTime(time);
    setCurrent(time);
    audio.onChangeTime(time, audio);
  };

  // eslint-disable-next-line @typescript-eslint/no-shadow
  const canplayCb = (duration: number) => {
    setDuration(duration);
    setLoading(false);
  };

  const endedCb = (bol: boolean) => {
    setPaused(bol);
    audio.onChangePlayCbk(false);
  };

  useEffect(() => {
    audio.timeupdateCb = timeupdateCb;
    audio.canplayCb = canplayCb;
    audio.endedCb = endedCb;
    return () => {
      yuqueVisible = true;
    };
  }, []);

  useEffect(() => {
    if (duration !== 0 && markPointList !== undefined) {
      const list: any = markPointList?.map((item: MarkPointParams) => {
        const time = formatHMSHover(Number(item.startTime.toFixed(0)));
        // eslint-disable-next-line @typescript-eslint/no-shadow
        const percent = (item.startTime / duration) * 100;
        return {
          startTime: item.startTime,
          percent,
          title: time,
          content: item.text,
          color: item.color,
        };
      });
      setTips(list);
    }
  }, [JSON.stringify(markPointList), duration]);

  useEffect(() => {
    let currentTimeArg = 0;
    let percentArg = 0;
    currentTimeArg = Math.round(current * 100) / 100;
    percentArg = Math.round((currentTimeArg / duration) * 10000) / 100;
    percentArg = Math.min(100, percentArg);
    setPercent(percentArg);
    setCurrentTime(currentTimeArg);
  }, [current, duration]);

  const changeCurrent = (e: any) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const offsetX = e.clientX - rect.left;
    const currentTimeArg = (offsetX / rect.width) * duration;
    changeSeek(currentTimeArg);
  };

  useEffect(() => {
    if (audio) {
      bus.on(CHANGESEEK, changeSeek);
      return () => {
        bus.off(CHANGESEEK, changeSeek);
      };
    }
  }, [audio]);

  const changeSeek = (currentTimeArg: number) => {
    if (audio) {
      audio.onSeek(audio, currentTimeArg);
      setCurrent(currentTimeArg);
    }
  };

  const changeTargetTime = (e: any) => {
    if (!audio || duration <= 0) return;
    const rect = e.currentTarget.getBoundingClientRect();
    let offsetX = e.clientX - rect.left;
    // const offsetY = e.clientY - rect.top;
    if (offsetX < 0) {
      offsetX = 0;
    }
    const currentTimeArg = (offsetX / rect.width) * duration;
    const time = formatHMSHover(Number(currentTimeArg.toFixed(0)));

    let text;
    let agendaSummary;

    if (!text) {
      markSegmentList.some((item: any) => {
        if (item.startTime <= currentTimeArg && currentTimeArg < item.endTime) {
          text = item.text;
          agendaSummary = item.agendaSummary;
          return true;
        }
        return false;
      });
    }

    const pointInfo = {
      time,
      text,
      offsetX,
      rectWidth: rect.width,
      agendaSummary,
      dotVisible: yuqueVisible,
    };
    setPointTimeBoxData(pointInfo);
  };

  useEffect(() => {
    bus.on(POINTTIMEINFOVISIBLE, setPointTimeInfo);
    return () => {
      bus.off(POINTTIMEINFOVISIBLE, setPointTimeInfo);
    };
  }, [duration]);

  const setPointTimeInfo = (info: any) => {
    setPointTimeBoxData(info);
  };

  const clearTargetTime = () => {
    setPointTimeBoxData({});
  };

  useEffect(() => {
    if (!controlRef?.current) return;

    const rect = controlRef?.current?.getBoundingClientRect();
    // console.log('rect ', rect);
    const width = rect.width || 436;
    setWrapperWidth(width);
  }, [controlRef?.current?.getBoundingClientRect()?.width]);

  // const dragEvent = (e: any) => {
  //   // emitter.emit(VideoEvents.timeupdateorder.key, true);
  //   e.preventDefault();
  //   e.stopPropagation();
  //   e.cancelBubble = true;
  //   const loc = e.clientX;
  //   setMouseLoc(loc); // 设置鼠标拖动滑块的位置
  //   setIsDrag(true); // 拖动状态
  // };

  // 鼠标 移动 进度条
  const mouseMoveEvent = useCallback(
    (e: any) => {
      // 如果不是拖动状态，return
      if (!audio || duration <= 0 || !isDrag) return;
      // emitter.emit(VideoEvents.timeupdateorder.key, true);
      const diff = ((e.clientX - (mouseLoc || 0)) / wrapperWidth) * duration;
      let newCurrent = currentTime + diff;
      newCurrent = Math.min(Math.max(0, newCurrent), duration);
      setMouseLoc(e.clientX);

      // 先移动位置，再seek
      setCurrent(newCurrent);
      debounce(() => audio.seek(newCurrent), 80, false);

      // onChange('seek', newCurrent + start);
    },
    [isDrag],
  );

  // 鼠标按键抬起--进度条
  const mouseUpEvent = (e: any) => {
    if (!audio || duration <= 0) return;
    // 设置是否是拖动状态
    setIsDrag(false);
    // 清除监听
    removeListener();
    // 获取 数值
    const diff = ((e.clientX - (mouseLoc || 0)) / wrapperWidth) * duration;
    let newCurrent = currentTime + diff;
    newCurrent = Math.min(Math.max(0, newCurrent), duration);
    // onChange('seek', newCurrent + start);
    audio.onSeek(audio, newCurrent);
  };

  // 监听拖动状态，并执行添加监听的函数， 并返回清除监听事件函数
  useEffect(() => {
    // 如果是拖动状态，则添加监听函数
    if (isDrag) {
      addListener();
    }
    return removeListener;
  }, [mouseMoveEvent]);

  // 添加 鼠标 监听事件
  const addListener = () => {
    document.body.addEventListener('mousemove', mouseMoveEvent);
    document.body.addEventListener('mouseup', mouseUpEvent);
    document.body.addEventListener('mouseleave', mouseUpEvent);
  };
  // 移除监听事件
  const removeListener = () => {
    document.body.removeEventListener('mousemove', mouseMoveEvent);
    document.body.removeEventListener('mouseup', mouseUpEvent);
    document.body.removeEventListener('mouseleave', mouseUpEvent);
  };

  // 片段高亮信息处理
  useEffect(() => {
    if (!audio || duration <= 0) {
      return;
    }
    // 添加highLight盒子的 宽与left属性，确定位置和大小
    const list: any = markSegmentList.map((i: any) => {
      const item = {
        ...i,
        leftValue: `${((i.startTime / duration) * 100).toFixed(2)}%`,
        widthValue: `${(((i.endTime - i.startTime) / duration) * 100).toFixed(
          2,
        )}%`,
      };
      return item;
    });

    setMarkSegData(list);
  }, [duration, JSON.stringify(markSegmentList)]);

  // 监听快捷按键
  const listenKeydown = (e: any) => {
    if (!audio || loading) return;
    if (e.keyCode === 32) {
      debounce(
        () => {
          let status = false;
          if (paused) {
            status = false;
          } else {
            status = true;
          }
          setPaused(status);
          if (!status) {
            audio.onPlay();
            audio.onChangePlayCbk(true);
          } else {
            audio.onPause();
            audio.onChangePlayCbk(false);
          }
        },
        80,
        false,
      )();
      // if (!paused) {
      //   audio.onPause();
      //   setPaused(true);
      //   audio.onChangePlayCbk(false);
      // } else {
      //   setPaused(false);
      //   audio.onPlay();
      //   audio.onChangePlayCbk(true);
      // }
    } else {
      if (isMac) {
        if (e.metaKey && e.keyCode === 37) {
          audio.onSeek(audio, currentTime, 'prev');
        } else if (e.metaKey && e.keyCode === 39) {
          audio.onSeek(audio, currentTime, 'next');
        }
      } else {
        if (e.ctrlKey && e.keyCode === 37) {
          audio.onSeek(audio, currentTime, 'prev');
        } else if (e.ctrlKey && e.keyCode === 39) {
          audio.onSeek(audio, currentTime, 'next');
        }
      }
    }
  };

  useEffect(() => {
    if (shortcutKey) {
      window.addEventListener('keydown', listenKeydown);
    } else {
      window.removeEventListener('keydown', listenKeydown);
    }
    return () => {
      window.removeEventListener('keydown', listenKeydown);
    };
  }, [shortcutKey, paused, currentTime, audio, loading]);

  const onChangeSwitch = (checked: boolean) => {
    audio.onChangeSkipBlank(checked);
    audio.onChangeSkipBlankCbk(checked);
    setSkipBlank(checked);
  };

  const onChangeVolume = useCallback(
    (newValue: number) => {
      if (newValue / 100 > 0 && muted) {
        SetMuted(false);
        audio.onMuted(false);
      }
      setVolume(newValue);
      audio.onChangeVolume(newValue / 100);
      audio.onChangeVolumeCbk(audio);
    },
    [setVolume, muted],
  );

  const speedTipsContent = useMemo(() => {
    return (
      <SpeedSelect
        onMouseOver={() => setSpeedTipsVisible(true)}
        onMouseOut={() => setSpeedTipsVisible(false)}
      >
        {audioRateList?.map((item: any, index: any) => {
          return (
            <div
              key={+index}
              className={`select_item ${speed === item && 'select_active'}`}
              onClick={() => {
                setSpeed(item);
                setSpeedTipsVisible(false);
                audio.onChangePlaybackRate(item);
                audio.onChangeSpeedCbk(audio);
              }}
            >
              {item}x
            </div>
          );
        })}
      </SpeedSelect>
    );
  }, [speed, JSON.stringify(audioRateList)]);

  const volumeTipsContent = useMemo(() => {
    return (
      <VolumeContent>
        <div className="skip_blank">
          <div>跳过空白片段</div>
          <Switch size="small" checked={skipBlank} onChange={onChangeSwitch} />
        </div>
        <div className="volume_bar">
          {muted || volume === 0 ? (
            <TYIcon
              type="tongyi-mute-line"
              onClick={() => {
                SetMuted(false);
                audio.onMuted(false);
                audio.onChangeVolumeCbk(audio);
              }}
            />
          ) : (
            <TYIcon
              type="tongyi-lowVolume-line"
              onClick={() => {
                SetMuted(true);
                audio.onMuted(true);
                audio.onChangeVolumeCbk(audio);
              }}
            />
          )}
          <Slider
            min={0}
            max={100}
            className="customSlider"
            value={muted ? 0 : volume}
            onChange={onChangeVolume}
            tipFormatter={null}
          />
          <span className="volume">{muted ? 0 : volume}%</span>
        </div>
      </VolumeContent>
    );
  }, [skipBlank, volume, muted]);

  // 音波图
  const waveContent = useMemo(() => {
    return (
      <AudioWaveWrap>
        <AudioWave
          audioData={spectrum}
          markSegData={markSegData}
          tips={tips}
          percent={percent}
          duration={duration}
        />
      </AudioWaveWrap>
    );
  }, [spectrum, tips, percent, duration]);

  const onPlay = useCallback((_audio: any, _paused: boolean) => {
    debounce(
      () => {
        let status = false;
        if (_paused) {
          status = false;
        } else {
          status = true;
        }
        setPaused(status);
        if (!status) {
          _audio.onPlay();
          _audio.onChangePlayCbk(true);
        } else {
          _audio.onPause();
          _audio.onChangePlayCbk(false);
        }
      },
      80,
      false,
    )();
  }, []);

  useEffect(() => {
    bus.on(YUWQUEVISIBLE_AUDIO, onYuequeVisible);
    return () => {
      bus.off(YUWQUEVISIBLE_AUDIO, onYuequeVisible);
    };
  }, []);

  const onYuequeVisible = (visible: boolean) => {
    yuqueVisible = visible;
  };

  return (
    <AudioPlayerControlBar data-e2e-test-id="trans_audioPlayer_div">
      <LeftControlBar>
        <Tooltip
          placement="top"
          color="#27264d"
          title={`${paused ? '播放' : '暂停'} ${
            isMac ? 'Option' : 'Shift'
          } + Space`}
          getPopupContainer={(triggerNode) => triggerNode.parentElement as any}
        >
          <PlayIconWrap
            className={`${loading && 'loading'}`}
            onClick={() => {
              if (loading) return;
              onPlay(audio, paused);
            }}
          >
            {paused ? (
              <TYIcon style={{ fontSize: 18 }} type="icon-play-fill" />
            ) : (
              <TYIcon style={{ fontSize: 18 }} type="icon-pause-fill" />
            )}
          </PlayIconWrap>
        </Tooltip>
      </LeftControlBar>
      <SliderWrap ref={controlRef}>
        {/* 音波图 */}
        {waveContent}
        <PointBox
          onClick={changeCurrent}
          onMouseEnter={changeTargetTime}
          onMouseMove={changeTargetTime}
          onMouseLeave={clearTargetTime}
          ref={(div) => {
            if (div) {
              try {
                const rects = div.getClientRects();
                contentWidth = rects[0]?.width || 0;
              } catch (error) {
                console.log('PointBox', error);
              }
            }
          }}
        >
          {/* hover时显示当前hover的时间 */}
          <TimeTooltip {...(pointTimeBoxData as TimeTooltipContent)} />

          <Bar>
            <div className="dotBar" style={{ width: `${percent}%` }} />
            <MarkWrap>
              {[...(markSegData || [])]?.map((item: any, index) => {
                if (!item.widthValue) return '';
                const { startTime, endTime, leftValue, widthValue } = item;

                // eslint-disable-next-line @typescript-eslint/no-shadow
                const percent = getSplitPercent(
                  [startTime, endTime],
                  currentTime,
                );

                return (
                  <div
                    className={`markSegment ${
                      hltMarkSegIndex === index ? 'hltMarkSegment' : ''
                    }`}
                    style={{
                      left: leftValue,
                      width: widthValue,
                    }}
                    key={`markSegment-${index}`}
                    onMouseEnter={() => {
                      if (isDrag) return;
                      setHltMarkSegIndex(index);
                    }}
                    onMouseLeave={() => {
                      setHltMarkSegIndex(-1);
                    }}
                  >
                    <div className="markSegmentInner">
                      <div
                        // ref={(div) => {
                        //   if (div && percent > 0 && percent < 100 && contentWidth > 0) {
                        //     try {
                        //       const rects = div.getClientRects();
                        //       const { left, width } = rects[0];
                        //       if (left !== undefined && width !== undefined) {
                        //         const _left = (left - 260) + width;
                        //         setTimeout(() => {
                        //           // bus.emit(CHANGECOVERWIDTH, `${contentWidth - _left - 2}px`);
                        //         }, 0);
                        //       }
                        //     } catch (error) {
                        //       console.log('markSegmentInner', error)
                        //     }
                        //   }
                        // }}
                        className="markSegmentProgress"
                        style={{
                          width: `calc(${percent}% + ${
                            4 * (+percent / 100)
                          }px)`,
                          maxWidth: '100%',
                        }}
                      />
                    </div>
                  </div>
                );
              })}
            </MarkWrap>
          </Bar>
        </PointBox>
        <span className="cur_time">
          {getFlexibleTime(currentTime * 1000 || 0)}
          {jumpTipsTime && (
            <span className="auddioPlayJumpTips">
              上次播放到{jumpTipsTime}处，已自动跳转
            </span>
          )}
        </span>
        <span className="total_time">{getFlexibleTime(duration * 1000)}</span>
      </SliderWrap>

      <RightControlBar>
        <Tooltip
          placement="top"
          color="#fff"
          title={speedTipsContent}
          getPopupContainer={(triggerNode) => triggerNode.parentElement as any}
          visible={speedTipsVisible}
          overlayStyle={{ zIndex: 99 }}
        >
          <div
            className={`speed ${loading && 'loading'}`}
            onMouseEnter={() => setSpeedTipsVisible(true)}
            onMouseLeave={() => setSpeedTipsVisible(false)}
            style={{ userSelect: 'none' }}
          >
            {speed === 1 ? '倍速' : `${speed}x`}
          </div>
        </Tooltip>

        <Popover
          placement="topRight"
          title={null}
          content={volumeTipsContent}
          getPopupContainer={(triggerNode) => triggerNode.parentElement as any}
        >
          <TYIcon
            type="extend-modify-line"
            style={{ fontSize: 20, color: '#615ced' }}
          />
        </Popover>
      </RightControlBar>
    </AudioPlayerControlBar>
  );
};

export default React.forwardRef(AudioController);
