import React, {
  useCallback,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from 'react';
// *** 二方库 ***
import { getFlexibleTime } from '@tingwujs/common';
// *** Model 层数据相关 ***
import { docPlayerHooks, docTagHooks } from '../../../../../../documentModel';
// *** 配置文件相关 ***
import { PLAYER_NEXT_HOT_KEY, PLAYER_PREV_HOT_KEY } from './hotkey.config';
// *** 工具相关 ***
import {
  getPercent,
  getSplitPercent,
  isMac,
} from '../../../../../../utils/misc';
// *** 快捷键相关 ***
import { useBaseHotkey } from '../../../../../../utils/hotkey';
// *** 内部UI组件 相关 ***
import type { iAudioStatus } from '../AudioCore';
import { AudioCore, eAudioCoreEvts } from '../AudioCore';
import { AudioPlayerCtrl } from '../AudioUI/AudioPlayerCtrl';
import { AudioPlayerOpts } from '../AudioUI/AudioPlayerOpts';
import {
  AudioTimeToolTip,
  iAudioTimeTooltipContent,
} from '../AudioUI/AudioTimeTooltip';
import { AudioWave } from '../AudioUI/AudioWave/AudioWave';
import { PlayerTime } from '../AudioUI/PlayerTime';
// *** 类型定义文件 ***
import type {
  iDocAudioPlayerProps,
  iDocAudioPlayerStatus,
  iTWDocPlayerHandler,
  tAudioPlayerState,
} from './TWDocAudioPlayer.type';
// *** 样式文件 ***
import { Editor_Reset_Caret } from '../../../../../../constants/recordEditor.constant';
import bus from '../../../../../../utils/bus';
import { TYIcon } from '@tingwujs/design';
import './TWDocAudioPlayer.less';

const TWDocAudioPlayer: React.ForwardRefRenderFunction<
  iTWDocPlayerHandler,
  iDocAudioPlayerProps
> = (props, audioControllerRef) => {
  // 保存 Controller 引用，避免多次更新
  const { controller } = props;
  const { docPlayerData } = docPlayerHooks.useDocPlayerData();
  const { docTagData } = docTagHooks.useDocTagData();
  const { audioStatus } = (docTagData || {}) as any;
  const { playerRecordTimeTipOpen, playerRecordTime } = docPlayerData || {};
  const controllerRef = useRef(controller);

  /** 内部管理状态 */

  const { initAudioStatus = {} } = props as any;
  const audioPlayerStateRef = useRef<tAudioPlayerState>({
    ...(initAudioStatus as iAudioStatus),
    audioIsLoading: false, // 是否加载中
    audioIsPlaying: false, // 音频是否播放中
    duration: 0,
    playPercent: 0,
    skipBlank: false, // 是否跳过空白片段
  });
  const [audioPlayerState, setAudioPlayerState] = useState<tAudioPlayerState>(
    audioPlayerStateRef.current,
  );

  const [isAudioLoading, setIsAudioLoading] = useState(false);

  useEffect(() => {
    if (controller) {
      controller?.setAudioLoading?.(audioStatus === '0');
    }
    controllerRef.current = controller;
  }, [controller, audioStatus]);

  useEffect(() => {
    setIsAudioLoading(audioStatus === '0');
  }, [audioStatus]);

  // 内外部状态同步、引用更新
  const {
    onAudioTimeUpdate,
    onAudioRateChange,
    onAudioSkipBlankChange,
    onAudioVolumeChange,
    onAudioPlayStatusChange,
    // onAudioSeek,
  } = props;
  const updateAudioPlayerState = useCallback(
    (newState: Partial<tAudioPlayerState>) => {
      const newAudioPlayerState = {
        ...audioPlayerStateRef.current,
        ...newState,
      };
      audioPlayerStateRef.current = newAudioPlayerState; //  播放进度 百分比 更新
      // 1. 内部状态同步
      setAudioPlayerState(newAudioPlayerState);

      // 2. 外部状态同步
      if (newState.currentTime !== undefined) {
        // 音频播放器时间单位 s, 同步到外部单位 ms
        onAudioTimeUpdate(newState.currentTime);
      }
      if (newState.playbackRate !== undefined) {
        onAudioRateChange(newState.playbackRate);
      }
      if (newState.skipBlank !== undefined) {
        onAudioSkipBlankChange(newState.skipBlank);
      }
      if (newState.volume !== undefined || newState.muted !== undefined) {
        onAudioVolumeChange(
          newAudioPlayerState.volume,
          newAudioPlayerState.muted,
        );
      }
      if (newState.audioIsPlaying !== undefined) {
        onAudioPlayStatusChange(newState.audioIsPlaying);
      }
    },
    [
      onAudioTimeUpdate,
      onAudioRateChange,
      onAudioSkipBlankChange,
      onAudioVolumeChange,
      onAudioPlayStatusChange,
    ],
  );

  // 音频时间更新
  let { audioSegments } = props;
  if (typeof audioSegments === 'string') {
    audioSegments = JSON.parse(audioSegments);
  }
  const audioSegmentsRef = useRef(audioSegments);
  useEffect(() => {
    audioSegmentsRef.current = audioSegments;
  }, [audioSegments]);

  /** 控制播放器 */
  // 音频播放器播放状态(音量、静音、倍数、跳过空白片段)
  const handlePlayerUpdate = useCallback(
    (status: iDocAudioPlayerStatus) => {
      const player = audioCoreRef.current;
      if (!player) return;
      // 1. 播放器同步 2. 状态同步
      const { volume, muted, curtTime, playbackRate, skipBlank } = status;
      const updateStatus: Partial<tAudioPlayerState> = {};

      // 音频状态变更控制
      if (volume !== undefined) {
        player.volume = volume;
        updateStatus.volume = volume;
      }
      if (muted !== undefined) {
        player.muted = muted;
        updateStatus.muted = muted;
      }
      if (curtTime !== undefined) {
        player.currentTime = curtTime / 1000; // 播放器内部时间（秒级s）
        updateStatus.currentTime = curtTime;
        // 当前时间更新，计算进度
        const playPercent = getPercent(
          curtTime,
          audioPlayerStateRef.current.duration,
        );
        updateStatus.playPercent = playPercent;
      }
      if (playbackRate !== undefined) {
        player.playbackRate = playbackRate;
        updateStatus.playbackRate = playbackRate;
      }
      // 业务状态变更。其他更新
      if (skipBlank !== undefined) {
        updateStatus.skipBlank = skipBlank;
      }

      // 业务状态同步变更
      updateAudioPlayerState(updateStatus);
    },
    [updateAudioPlayerState],
  );

  // 时间更新，计算跳过空白片段
  const upAudioTimeUpdate = useCallback(
    (time: number) => {
      const updateStatus: Partial<tAudioPlayerState> = {};
      const currentTime = time * 1000;
      updateStatus.currentTime = currentTime;

      // 1. 计算播放百分比
      const { duration } = audioPlayerStateRef.current;
      const playPercent = getPercent(currentTime, duration);
      updateStatus.playPercent = playPercent;

      // 跳过空白片段计算
      const { skipBlank } = audioPlayerStateRef.current;
      if (skipBlank) {
        const times = audioSegmentsRef.current.find(
          (item: number[], index: number) => {
            const prevEndTime = audioSegmentsRef.current[index - 1]?.[1] || 0;
            return currentTime > prevEndTime && currentTime < item[0];
          },
        );
        if (times) {
          const newStartTime = times[0];
          // 超过 100ms 才跳过空白片段
          if (newStartTime - currentTime > 100) {
            // 音频切换到指定时间
            handlePlayerUpdate({ curtTime: newStartTime });
            updateStatus.currentTime = newStartTime;
          }
        }
      }

      // 更新数据
      updateAudioPlayerState(updateStatus);
    },
    [handlePlayerUpdate, updateAudioPlayerState],
  );

  /** 核心音频播放器 */
  const audioCoreRef = useRef<AudioCore>();
  // 初始化音频播放器
  const { audioUrl } = props;
  useEffect(() => {
    if (!audioCoreRef.current) {
      // console.log('audio canplay audioIsLoading true');
      updateAudioPlayerState({ audioIsLoading: true });
      const audioCorePlayer = new AudioCore({
        audioSrc: audioUrl,
      });
      audioCoreRef.current = audioCorePlayer;
      // 事件监听绑定（加载完成可以播放）
      audioCorePlayer.once(eAudioCoreEvts.canplay, () => {
        // console.log('audio canplay audioIsLoading false');
        updateAudioPlayerState({ audioIsLoading: false });
      });
      // 总时间更新
      audioCorePlayer.on(eAudioCoreEvts.durationchange, (duration: number) => {
        // 状态同步，秒级别
        updateAudioPlayerState({ duration: duration * 1000 });
      });
      // 播放时间更新
      audioCorePlayer.on(eAudioCoreEvts.timeupdate, upAudioTimeUpdate);
      // 播放结束
      audioCorePlayer.on(eAudioCoreEvts.ended, () => {
        updateAudioPlayerState({ audioIsPlaying: false });
      });
    }

    return () => {
      const audioInst = audioCoreRef.current;
      if (audioInst) {
        if (audioInst.isPlaying) {
          audioInst.pause();
        }
        audioCoreRef.current?.destroy();
        audioCoreRef.current = undefined;
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [audioUrl, upAudioTimeUpdate]);

  // 控制播放器进行播放、暂停
  const clickTogglePlay = useCallback(async () => {
    const player = audioCoreRef.current;
    if (!player) return;

    // 播放控制
    try {
      if (audioPlayerStateRef.current.audioIsPlaying) {
        await player.pause();
        onAudioPlayStatusChange(false);
        updateAudioPlayerState({ audioIsPlaying: false });
      } else {
        await player.play();
        onAudioPlayStatusChange(true);
        updateAudioPlayerState({ audioIsPlaying: true });
      }
    } catch (e) {
      console.error('音频播放失败', e);
    }
  }, [updateAudioPlayerState, onAudioPlayStatusChange]);

  // 对外透出方法
  const audioPlayerToTime = useCallback(
    (time: number) => {
      handlePlayerUpdate({ curtTime: time });
    },
    [handlePlayerUpdate],
  );

  const audioStartPlayOnTime = useCallback(
    async (time: number) => {
      handlePlayerUpdate({ curtTime: time });
      await audioCoreRef.current?.play();
      onAudioPlayStatusChange(true);
      updateAudioPlayerState({ audioIsPlaying: true });
    },
    [handlePlayerUpdate, onAudioPlayStatusChange, updateAudioPlayerState],
  );

  const audioPlayerPause = useCallback(() => {
    audioCoreRef.current?.pause();
    updateAudioPlayerState({ audioIsPlaying: false });
  }, [updateAudioPlayerState]);

  /** 内部控制: (播放器按钮控制) */
  const { onAudioSeek } = props;
  // 播放上一句
  const onAudioPlayBack = useCallback(() => {
    const { currentTime } = audioPlayerStateRef.current;
    const _controller = controllerRef.current;

    if (_controller && currentTime !== undefined) {
      const result = _controller.getPrevSentencesByTime(currentTime);
      if (result.length > 0) {
        const newTime = result[0].beginTime;
        handlePlayerUpdate({ curtTime: newTime }); // 音频播放器时间同步
        onAudioSeek(newTime);
      }
    }
  }, [handlePlayerUpdate, onAudioSeek]);
  // 播放下一句
  const onAudioPlayNext = useCallback(() => {
    const { currentTime } = audioPlayerStateRef.current;
    const _controller = controllerRef.current;

    if (_controller && currentTime !== undefined) {
      const result = _controller.getNextSentencesByTime(currentTime);
      if (result.length > 0) {
        const newTime = result[0].beginTime;
        handlePlayerUpdate({ curtTime: newTime }); // 音频播放器时间同步
        onAudioSeek(newTime);
      }
    }
  }, [handlePlayerUpdate, onAudioSeek]);

  // 控制转发
  useImperativeHandle(
    audioControllerRef,
    () => ({
      audioPlayerToTime,
      audioStartPlayOnTime,
      audioPlayerPause,
      syncToAudioPlayer: handlePlayerUpdate,
    }),
    [
      audioPlayerToTime,
      audioStartPlayOnTime,
      audioPlayerPause,
      handlePlayerUpdate,
    ],
  );

  /** 快捷注册 */
  const { hotKeyEnabled = true } = props;
  const { audioIsLoading } = audioPlayerState;
  // 播放上一句 快捷键
  useBaseHotkey(PLAYER_PREV_HOT_KEY, onAudioPlayBack, {
    disabled: audioIsLoading ? true : !hotKeyEnabled,
  });

  // 播放下一句 快捷键
  useBaseHotkey(PLAYER_NEXT_HOT_KEY, onAudioPlayNext, {
    disabled: audioIsLoading ? true : !hotKeyEnabled,
  });

  useBaseHotkey('space', () => clickTogglePlay(), {
    disabled: audioIsLoading ? true : !hotKeyEnabled,
  });

  // 切换播放态 快捷键
  // 编辑器focus支持音频快捷键（必须绑定到document.body上）
  useEffect(() => {
    if (!hotKeyEnabled) return;
    const handlePlayerHotkey = (e: KeyboardEvent) => {
      if ((isMac ? e.altKey : e.shiftKey) && e.code === 'Space') {
        e.stopPropagation();
        e.preventDefault();
        clickTogglePlay();
        bus.emit(Editor_Reset_Caret);
      }
    };

    document.body.addEventListener('keydown', handlePlayerHotkey);

    return () => {
      document.body.removeEventListener('keydown', handlePlayerHotkey);
    };
  }, [clickTogglePlay, hotKeyEnabled]);

  // 大模型相关数据展示
  const { mediaAgendas, mediaTokens } = props;
  /** 播放器 Hover、Seek 等操作 */
  // 鼠标hover在进度条上时的进度信息框配置
  const [audioTimeTipContent, setAudioTimeTipContent] = useState<
    iAudioTimeTooltipContent | undefined
  >();
  const [AudioTimeToolTipDisabled, setIsAudioTimeToolTipDisabled] =
    useState(false);
  const mouseIsHoverOnAgendaRef = useRef(false); // 鼠标是否 Hover 到摘要上

  const handleHitMark = useCallback((isHit: boolean) => {
    setIsAudioTimeToolTipDisabled(isHit);
  }, []);

  const handleAudioTargetTimeChange = useCallback(
    (params?: {
      targetTime: number; // 目标时间
      width: number; // 展示宽度
      offsetX: number; // 鼠标偏移量
    }) => {
      if (!params) {
        setAudioTimeTipContent(undefined);
        return;
      }

      const { targetTime, width, offsetX } = params;
      // 需要显示的 Agenda
      const agendasDiffTime = Math.floor(targetTime);
      const hoverAgenda = mediaAgendas.find((item) => {
        if (
          item.startTime <= agendasDiffTime &&
          agendasDiffTime < item.endTime
        ) {
          return true;
        }
        return false;
      });
      const mouseIsHoverOnAgenda = mouseIsHoverOnAgendaRef.current;

      setAudioTimeTipContent({
        displayTime: getFlexibleTime(agendasDiffTime),
        offsetX,
        rectWidth: width,
        mediaAgenda: mouseIsHoverOnAgenda ? hoverAgenda : undefined,
      });
    },
    [mediaAgendas],
  );
  // 鼠标点击切换当前时间
  const onMouseClickToChangeCurrentTime = useCallback(
    (e: any) => {
      // 这里
      const { duration } = audioPlayerStateRef.current;
      const rect = e.currentTarget?.getBoundingClientRect();
      const offsetX = e.clientX - rect.left;
      const currentTimeArg = (offsetX / rect.width) * duration;
      // 切换当前时间
      handlePlayerUpdate({ curtTime: currentTimeArg });
      onAudioSeek(currentTimeArg);
    },
    [handlePlayerUpdate, onAudioSeek],
  );
  // 鼠标 Hover 目标时间
  const onMouseEvtToChangeTargetTime = useCallback(
    (e: any) => {
      const { duration } = audioPlayerStateRef.current;
      const audioPlayer = audioCoreRef.current;
      if (!audioPlayer || duration <= 0) return;
      // 计算目标时间
      const { left, width } = e.currentTarget.getBoundingClientRect();
      let offsetX = e.clientX - left;
      if (offsetX < 0) {
        offsetX = 0;
      }
      const targetTime = (offsetX / width) * duration;

      handleAudioTargetTimeChange({
        targetTime,
        width,
        offsetX,
      });
    },
    [handleAudioTargetTimeChange],
  );
  // 鼠标移除，清除目标时间
  const onMouseLeaveClear = () => {
    handleAudioTargetTimeChange(undefined);
  };

  // 音频数据
  const { audioSpectrum } = props;
  return (
    <div className="TWDocAudioPlayer">
      <AudioPlayerCtrl
        isLoading={audioPlayerState.audioIsLoading || isAudioLoading}
        isPlaying={audioPlayerState.audioIsPlaying}
        playBeforeClick={onAudioPlayBack}
        togglePlay={clickTogglePlay}
        palyNextClick={onAudioPlayNext}
      />
      {isAudioLoading ? (
        <div
          className="TWDocAudioPlayer-SliderWrap"
          style={{ position: 'relative' }}
        >
          <div className="TWDocAudioPlayer-LoadingSlider" />
          <div className="LoadingSlider_tips">
            <TYIcon type="icon-loader-01" className="loadingIcon" />
            音频加载中，请稍后
          </div>
        </div>
      ) : (
        <div className="TWDocAudioPlayer-SliderWrap">
          {/* 音波图 */}
          <div className="TWDocAudioPlayer-SliderWrap__AudioWaveWrapper">
            <AudioWave
              audioSpectrum={audioSpectrum}
              audioDuration={audioPlayerState.duration}
              playPercent={audioPlayerState.playPercent}
              hasAgenda={!!mediaAgendas.length}
              mediaTokens={mediaTokens}
              changeAudioTargetTime={handleAudioTargetTimeChange}
              changeToAudioTime={audioPlayerToTime}
              onHitMark={handleHitMark}
            />
          </div>
          {/* 进度条 */}
          <div
            className="TWDocAudioPlayer-SliderWrap__TimeBarWrap"
            onClick={onMouseClickToChangeCurrentTime}
            onMouseEnter={onMouseEvtToChangeTargetTime}
            onMouseMove={onMouseEvtToChangeTargetTime}
            onMouseLeave={onMouseLeaveClear}
          >
            {/* hover时显示当前hover的时间 */}
            {!AudioTimeToolTipDisabled && (
              <AudioTimeToolTip tipContent={audioTimeTipContent} />
            )}

            <div className="AudioTimeBar">
              {/* 百分比进度条 */}
              <div
                className="AudioPercentBar"
                style={{ width: `${audioPlayerState.playPercent}%` }}
              />
              {/* 章节速览分段 */}
              <div className="AudioAgendaSummaryItem">
                {(mediaAgendas || []).map((item) => {
                  const { startTime, endTime } = item;
                  const { currentTime } = audioPlayerState;
                  const { duration } = audioPlayerState;

                  const leftValue = `${((startTime / duration) * 100).toFixed(
                    2,
                  )}%`;
                  const widthValue = `${(
                    ((endTime - startTime) / duration) *
                    100
                  ).toFixed(2)}%`;

                  const percent = getSplitPercent(
                    [startTime, endTime],
                    currentTime,
                  );

                  return (
                    <div
                      className="AudioAgendaSummaryItem-Bar"
                      style={{
                        left: leftValue,
                        width: widthValue,
                      }}
                      key={`markSegment-${item.id}`}
                      onMouseOverCapture={() => {
                        mouseIsHoverOnAgendaRef.current = true;
                      }}
                      onMouseOut={() => {
                        mouseIsHoverOnAgendaRef.current = false;
                      }}
                    >
                      <div className="AudioAgendaSummaryItem-Bar_ProgressWrap">
                        <div
                          className="progress"
                          style={{
                            width: `calc(${percent}% + ${
                              4 * (+percent / 100)
                            }px)`,
                            maxWidth: '100%',
                          }}
                        />
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>

          <span>
            <PlayerTime
              className="cur_time"
              time={audioPlayerState.currentTime}
              extraNode={
                playerRecordTimeTipOpen && !!playerRecordTime ? (
                  <span className="auddioPlayJumpTips">
                    上次播放到{getFlexibleTime(playerRecordTime)}处，已自动跳转
                  </span>
                ) : null
              }
            />
          </span>
          <PlayerTime className="total_time" time={audioPlayerState.duration} />
        </div>
      )}

      <AudioPlayerOpts
        isLoading={audioPlayerState.audioIsLoading || isAudioLoading}
        muted={audioPlayerState.muted}
        onChangeMuted={(muted: boolean) => handlePlayerUpdate({ muted })}
        rate={audioPlayerState.playbackRate}
        onChangeRate={(playbackRate: number) =>
          handlePlayerUpdate({ playbackRate })
        }
        volume={audioPlayerState.volume}
        onChangeVolume={(volume: number) => handlePlayerUpdate({ volume })}
        isSkipBlank={audioPlayerState.skipBlank}
        onChangeSkipBlank={(skipBlank: boolean) =>
          handlePlayerUpdate({ skipBlank })
        }
      />
    </div>
  );
};

const forwardRefTWDocAudioPlayer = React.forwardRef(TWDocAudioPlayer);
export { forwardRefTWDocAudioPlayer as TWDocAudioPlayer };
