import * as React from "react";
import * as R from "ramda";
import { ViewStyle } from "react-native";
import {
  findPluginByType,
  findPluginByIdentifier,
} from "@applicaster/zapp-react-native-utils/pluginUtils";
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";

import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
import { PlayerContainer } from "../PlayerContainer";

type Props = {
  item: ZappEntry;
  isModal: boolean;
  modalHeight?: number;
  modalWidth?: number;
  mode: VideoModalMode;
  groupId?: string;
};

const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
const CHROMECAST_PLUGIN_ID = "chromecast_qb";

const getPlayerWithModuleProperties = (
  PlayerModule: ZappPlugin
): [ZappPlugin, PlayerModuleProperties] => {
  const getPlayerModuleProperties = R.ifElse(
    R.is(Object) && R.has("Component"),
    R.omit(["Component"]),
    () => ({})
  );

  return [
    PlayerModule?.Component || PlayerModule,
    getPlayerModuleProperties(PlayerModule),
  ];
};

const getPlayer = (
  item: ZappEntry,
  state
): [ZappPlugin, PlayerModuleProperties] => {
  const {
    plugins,
    contentTypes,
    rivers,
    appData: { layoutVersion },
  } = state;

  let PlayerModule;

  if (layoutVersion === "v2") {
    const { screen_id } = contentTypes?.[item?.type?.value] || {};
    const { type } = rivers?.[screen_id] || {};

    if (type) {
      PlayerModule = findPluginByIdentifier(type, plugins)?.module;

      return getPlayerWithModuleProperties(PlayerModule);
    }
  }

  if (item?.content?.type === "youtube-id") {
    PlayerModule = findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins)?.module;

    return getPlayerWithModuleProperties(PlayerModule);
  }

  PlayerModule = findPluginByType(
    "playable",
    plugins.filter(({ identifier }) => identifier !== YOUTUBE_PLUGIN_ID)
  );

  return getPlayerWithModuleProperties(PlayerModule);
};

const dimensionsContext: "window" | "screen" = platformSelect({
  android_tv: "window",
  amazon: "window",
  default: "screen",
});

type PlayableComponent = {
  Component: React.ComponentType<any>;
};

export function HandlePlayable({
  item,
  isModal,
  modalHeight,
  modalWidth,
  mode,
  groupId,
}: Props): React.ReactElement | null {
  const state = usePickFromState();

  const { width: screenWidth, height: screenHeight } =
    useDimensions(dimensionsContext);

  const { closeVideoModal } = useNavigation();

  const [Player, playerModuleProperties] = getPlayer(item, state);

  const { module: CastPlugin } =
    findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};

  const [playable, setPlayable] =
    React.useState<Nullable<PlayableComponent>>(null);

  const [casting, setCasting] = React.useState(CastPlugin?.isCasting);

  React.useEffect(() => {
    // close video modal before open non-modal player
    if (!isModal) {
      closeVideoModal();
    }
  }, []);

  React.useEffect(() => {
    const castStateHandler = async () => {
      const castState = await CastPlugin?.getCastState();
      setCasting(castState === "Connected");
    };

    castStateHandler();

    CastPlugin?.EventEmitter?.addListener?.(
      CastPlugin?.CAST_STATE_CHANGED,
      castStateHandler
    );

    return () => {
      CastPlugin?.EventEmitter?.removeListener?.(
        CastPlugin?.CAST_STATE_CHANGED,
        castStateHandler
      );
    };
  }, []);

  React.useEffect(() => {
    if (casting) {
      setPlayable({ Component: CastPlugin?.CastHandler });
    } else {
      setPlayable({ Component: PlayerContainer });
    }
  }, [casting]);

  const Component = playable?.Component;

  const style = React.useMemo(
    () => ({
      width: isModal ? modalWidth : mode === "PIP" ? "100%" : screenWidth,
      height: isModal ? modalHeight : mode === "PIP" ? "100%" : screenHeight,
    }),
    [screenWidth, screenHeight, modalHeight, modalWidth, isModal, mode]
  );

  if (Component) {
    return (
      <Component
        item={item}
        Player={Player}
        plugin={CastPlugin}
        style={style}
        isModal={isModal}
        mode={mode}
        disableCastAction={playerModuleProperties?.disableCastAction}
        groupId={groupId}
      />
    );
  }

  return !isModal ? <BufferAnimation videoStyle={style as ViewStyle} /> : null;
}
