import * as R from "ramda";
import { ASSETS, STYLES } from "./Keys";

import {
  populateConfigurationValues as _populateConfigurationValues,
  flattenFields,
} from "../configurationUtils";
import { applyTransform, transformColorCode } from "../transform";
import { ManifestField } from "../types";
import { stylesUtilsLogger } from "./logger";

// TODO replace to valid type
type TRemoteConfiguration = Record<string, unknown>;

/**
 * returns the color value of a given style
 * @param {string} color name of color style to pick
 * @param {Object} appStyles dictionary of styles for the app
 * @returns {string} color string for the requested style
 */
export function getAppStylesColor(color: string, appStyles: {}): string {
  return R.compose(
    transformColorCode,
    R.defaultTo(""),
    R.path([color, "color"])
  )(appStyles || {});
}

/**
 * This call is quite safe:
 * - cellStyles is always initialized as an empty object by default in the redux store.
 * - component.styles is always present
 * Take care: The returned cellStyle can be undefined, component should provide fallback or throw.
 * @param {object} cellStyles     From cell_styles.json - map of ids to master cells
 * @param {object} component      UI component from layout.json
 * @returns {(object|undefined)}  Master Cell || Cell Styles Plugin configuration || undefined
 */
export function extractMasterCell({ cellStyles, component: { styles } }) {
  const masterCell = cellStyles[styles.master_cell_id];

  if (!masterCell) {
    return undefined;
  }

  // TODO: Support master cells that have a plugin configuration
  // For now this is just a safety fallback to prevent crashes during
  // development of the cell-styles-as-plugins feature
  if (masterCell.plugin_identifier) {
    return undefined;
  }

  return masterCell;
}

/**
 * retrieves an app property from remote configurations
 * @param {string} prop "styles" | "assets"
 * @param {string} key
 * @param {Object} remoteConfigurations
 * @returns {string}
 */
function getAppProperty(
  prop: "styles" | "assets",
  key: string,
  remoteConfigurations: TRemoteConfiguration
): string {
  const APP_PROPS = {
    styles: STYLES,
    assets: ASSETS,
  };

  const appProperties = APP_PROPS[prop];

  const propPath = R.path([prop, "tv"], remoteConfigurations)
    ? "tv"
    : "universal";

  if (!R.keys(appProperties).includes(key)) {
    stylesUtilsLogger.warning({
      message: `Requesting unknown asset ${key} - check the available assets:`,
    });
  }

  return R.path([prop, propPath, appProperties[key]], remoteConfigurations);
}

/**
 * retrieves an asset
 * @param {string} assetKey
 * @param {Object} remoteConfigurations
 * @returns {string}
 */
export function getAppAsset(
  assetKey: string,
  remoteConfigurations: TRemoteConfiguration
): string {
  return getAppProperty("assets", assetKey, remoteConfigurations);
}

/**
 * retrieves a style key
 * @param {string} assetKey
 * @param {Object} remoteConfigurations
 * @returns {string}
 */

export function getAppStyle(
  styleKey: string,
  styles: TRemoteConfiguration
): string {
  return getAppProperty("styles", styleKey, { styles });
}

/**
 * This function takes 2 styles objects in key:value pairs,
 * remove all undefined values and return merged styles.
 * @param {object} defaultStyle default fallback styles in key:value pairs
 * @param {object} customStyle remote configuration of styles in key:value pairs
 * @returns {(object|undefined)} merged styles in key:value pairs
 */
export function mergeStyles(defaultStyle, customStyle) {
  const filteredCustomStyle = R.reject(R.isNil, customStyle);

  return { ...defaultStyle, ...filteredCustomStyle };
}

/**
 * This function is mapping default styles from plugin manifest to styles
 * in ke:value pairs
 * @param {object} styles - object from manifest structure styles.fields
 * @returns styles in key:value pairs
 */
export function parseDefaultStyles(
  styles: ManifestField<any>[]
): Record<string, Nullable<string | number>> {
  return R.compose(
    R.reduce((acc, { type, key, initial_value }) => {
      return R.assoc(key, applyTransform(type)(initial_value), acc);
    }, {}),
    flattenFields
  )(styles);
}

/**
 * @deprecated Use "@applicaster/zapp-react-native-utils/configurationUtils"
 */
export const fixColorHexCode = (colorHex: string): string => {
  __DEV__ &&
    stylesUtilsLogger.warning(
      'Deprecated, please modify import from "@applicaster/zapp-react-native-utils/stylesUtils"  to "@applicaster/zapp-react-native-utils/configurationUtils"'
    );

  return transformColorCode(colorHex);
};

/**
 * @deprecated Use "@applicaster/zapp-react-native-utils/configurationUtils"
 */
export const populateConfigurationValues = (...args) => {
  __DEV__ &&
    stylesUtilsLogger.warning(
      'Deprecated, please modify import from "@applicaster/zapp-react-native-utils/stylesUtils"  to "@applicaster/zapp-react-native-utils/configurationUtils"'
    );

  return _populateConfigurationValues(...args);
};
