import { FC, useContext, useEffect } from "react";
import { observer } from "mobx-react";
import { KrpanoRendererContext } from "../contexts";
import { videoSceneModel } from "../models";

export interface VideoSceneProps {
  name: string;
  videointerfaceXmlUrl: string;
  videoplayerUrl: string;
  /**
   * 视频源列表
   * @example
   * [{
   *   // 分辨率
   *   res: '1920x960',
   *   // | 分割视频文件 url，krpano会自动根据浏览器的兼容性选择合适的视频格式播放
   *   url: '/path/video-1920x960.mp4|/path/video-1920x960.webm',
   *   // 封面图片 url
   *   poster: '/path/video-1920x960-poster.jpg'
   * }]
   */
  sourceList: {
    res: string;
    url: string;
    poster: string;
  }[];
  /**
   * 播放分辨率
   * @example '1920x960'
   */
  playRes: string;
  /**
   * 插件属性，参数见文档
   * @see https://krpano.com/plugins/videoplayer/#attributes
   * @default
   * {
   *   loop: true,
   *   volume: 0
   * }
   */
  pluginAttrs?: {
    loop?: boolean;
    volume?: number;
  };
  /**
   * 视图属性，参数见文档
   * @see https://krpano.com/docu/xml/#view
   */
  viewAttrs?: Record<string, unknown>;
  /**
   * 页面可见状态发生变化回调
   */
  onVisibility?: () => void;
}

const DEFAULT_PLUGIN_ATTRS = {
  loop: true,
  volume: 0,
};

const DEFAULT_VIEW_ATTRS = {
  hlookat: 0,
  vlookat: 0,
  fovtype: "DFOV",
  fov: 120,
  fovmin: 80,
  fovmax: 130,
  distortion: 0,
};

export const VideoScene: FC<VideoSceneProps> = observer(
  ({
    name,
    videointerfaceXmlUrl,
    videoplayerUrl,
    sourceList,
    playRes,
    pluginAttrs,
    viewAttrs,
    onVisibility,
  }) => {
    const renderer = useContext(KrpanoRendererContext);
    const model = videoSceneModel;

    const getSourceListStr = () => {
      let str = "";
      sourceList.forEach((item) => {
        str += `videointerface_addsource('${item.res}', '${item.url}', '${item.poster}');`;
      });
      return str;
    };

    const objectToString = (obj: Record<string, unknown>) => {
      let stack: string[] = [];

      Object.keys(obj).forEach((key) => {
        stack.push(`${key}="${obj[key]}"`);
      });

      return stack.join(" ");
    };

    const visibilityHandler = () => {
      if (document.visibilityState === "hidden") {
        model.pause();
      }

      onVisibility?.();
    };

    const wechatJSReadyHandler = () => {
      model.playing && model.play();
    };

    useEffect(() => {
      window.addEventListener("visibilitychange", visibilityHandler);
      document.addEventListener(
        "WeixinJSBridgeReady",
        wechatJSReadyHandler,
        false
      );

      return () => {
        window.removeEventListener("visibilitychange", visibilityHandler);
        document.removeEventListener(
          "WeixinJSBridgeReady",
          wechatJSReadyHandler
        );
      };
    }, []);

    useEffect(() => {
      if (!renderer) return;

      const _pluginAttrs = objectToString(
        Object.assign({}, DEFAULT_PLUGIN_ATTRS, pluginAttrs, {
          pausedonstart: !model.playing,
        })
      );
      const _viewAttrs = objectToString(
        Object.assign({}, DEFAULT_VIEW_ATTRS, viewAttrs)
      );

      renderer.tagAction.pushSyncTag(
        "scene",
        {
          name,
        },
        `
          <!-- include the videoplayer interface / skin -->
          <include url="${videointerfaceXmlUrl}" />

          <!-- include the videoplayer plugin -->
          <plugin ${_pluginAttrs} name="video"
            url="${videoplayerUrl}"
            onloaded="add_video_sources();"
          />

          <!-- use the videoplayer plugin as panoramic image source -->
          <image>
            <sphere url="plugin:video" />
          </image>

          <!-- set the default view -->
          <view ${_viewAttrs} />

          <action name="add_video_sources" >
            ${getSourceListStr()}

            videointerface_play('${playRes}');
          </action>
        `
      );
    }, [renderer]);

    return <div className="video-scene" />;
  }
);
