import {
  loadAppContextData,
  useAppDispatch,
  useActions,
} from "@applicaster/zapp-react-native-redux";
import * as R from "ramda";
import * as React from "react";
import axios from "axios";

import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";

import { useFeedLoader } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useFeedLoader";

import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";

import {
  setAppNotReady,
  setAppReady,
} from "@applicaster/zapp-react-native-redux/appState";

import {
  findRiver,
  getKeyFromStorage,
  handlePresentNavigation,
  isInternalUrl,
} from "../../helpers";

import { log_error, log_info } from "../../logger";
import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks/state";

const getFeed = (query) => ({
  content: { src: query.data_source },
  screen_type: query.screen_id,
});

export function usePresentSchemeHandler({
  query,
  url,
  onFinish,
}: UrlSchemeHandlerArgs) {
  const {
    screen_id,
    data_source,
    entry_id,
    rivers_configuration_id,
    resumeTime,
    link_url,
    show_nav_bar,
    content_type,
  } = query;

  React.useEffect(() => {
    log_info(`Handling present url ${url}`, { query });
  }, []);

  const navigator = useNavigation();

  const { data: feedData } = useFeedLoader({
    feedUrl: data_source,
  });

  const rivers = useRivers();
  const screenRiver = findRiver({ screen_id, rivers });
  const dispatch = useAppDispatch();

  const actions = useActions({
    setAppReady,
    setAppNotReady,
  });

  const navigateTo = React.useCallback(
    (data) => {
      onFinish((done) => {
        handlePresentNavigation({
          data,
          navigator,
          pushScreen: isInternalUrl(url) || link_url,
        });

        done?.();
      });
    },
    [onFinish, navigator, rivers, url]
  );

  const setCustomLayout = React.useCallback(
    async ({ rivers_configuration_id }) => {
      let sessionData: Partial<SessionStorageKeys> = {};

      try {
        sessionData = await sessionStorage.getAllItems("applicaster.v2");

        // ios returns accountsAccountID, while android has accountsAccountId
        // until this is aligned, we're pulling both values and use the one that
        // isn't undefined

        const accountKey = sessionData.accountsAccountId
          ? "accountsAccountId"
          : "zapp_account_id";

        // @ts-ignore - to be fixed on iOS side
        // key accountsAccountID should be accountsAccountId
        const accountId = getKeyFromStorage(accountKey, sessionData);

        const appBundleIdentifier = getKeyFromStorage(
          "bundleIdentifier",
          sessionData
        );

        const versionName = getKeyFromStorage("version_name", sessionData);

        const familyId = getKeyFromStorage("app_family_id", sessionData);

        const storeKey = getKeyFromStorage("store", sessionData);

        const WEB_STORE_PLATFORM: Record<string, string> = {
          samsung: "samsung_app_store",
          lg: "lg_content_store",
          vizio: "vizio_app_store",
        };

        const cdnStoreKey = WEB_STORE_PLATFORM[storeKey] ?? storeKey;

        const riversUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/apps/${appBundleIdentifier}/${cdnStoreKey}/${versionName}/layouts/${rivers_configuration_id}.json`;

        const cellStylesUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/app_families/${familyId}/layouts/${rivers_configuration_id}/cell_styles.json`;

        const presetsMappingUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/app_families/${familyId}/layouts/${rivers_configuration_id}/presets_mapping.json`;

        actions?.setAppNotReady();

        const { data: newRivers } = await axios.get(riversUrl);
        const { data: cellStyles } = await axios.get(cellStylesUrl);

        const presetsMapping = await axios
          .get(presetsMappingUrl)
          .then(({ data }) => data)
          .catch(noop);

        loadAppContextData(dispatch, {
          cellStyles,
          rivers: newRivers,
          contentTypes: newRivers.content_types,
          presetsMapping,
        });

        const homeRiver = R.compose(
          R.find(R.propEq("home", true)),
          R.ifElse(R.has("screens"), R.prop("screens"), R.values)
        )(newRivers);

        await sessionStorage.setItem(
          "rivers_configuration_id",
          rivers_configuration_id
        );

        onFinish((done) => {
          actions?.setAppReady();
          navigator.replace(homeRiver);
          done?.();
        });
      } catch (error) {
        log_error(`Cannot handle present url ${url}`, {
          query,
          error: error.message,
          sessionData,
        });

        onFinish((done) => {
          actions?.setAppReady();
          navigator.goHome();
          done?.();
        });
      }
    },
    []
  );

  const getFeedEntry = React.useCallback(
    () =>
      query.entry_id
        ? R.compose(
            R.when(
              () => resumeTime,
              R.assocPath(["extensions", "resumeTime"], resumeTime)
            ),
            R.find(R.propEq("id", entry_id))
          )(feedData?.entry || [])
        : getFeed(query),
    [feedData, query]
  );

  const getLinkEntry = React.useCallback(() => {
    const linkEntry: ZappEntry = {
      id: "url_scheme_entry",
      type: { value: content_type || "link" },
      link: {
        type: "text/html",
        href: decodeURIComponent(link_url),
      },
      extensions: {
        showNavBar: show_nav_bar === "true",
      },
    };

    if (screenRiver) {
      linkEntry.screen_type = screenRiver.id;
    }

    return linkEntry;
  }, [show_nav_bar, link_url]);

  if (link_url) {
    navigateTo(getLinkEntry());
  } else if (rivers_configuration_id) {
    setCustomLayout({ rivers_configuration_id });
  } else if ((data_source || entry_id) && feedData) {
    navigateTo(getFeedEntry());
  } else if (screenRiver) {
    navigateTo(screenRiver);
  } else if (!!screen_id && !screenRiver) {
    throw new Error("сan not proceed this URL");
  }
}
