import _typeof from "@babel/runtime/helpers/esm/typeof";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import React from 'react';
import { token2CSSVar, useCSSVarRegister, useStyleRegister } from '@ant-design/cssinjs';
import genCalc from "./calc";
import getCompVarPrefix from "./getCompVarPrefix";
import getComponentToken from "./getComponentToken";
import getDefaultComponentToken from "./getDefaultComponentToken";
import genMaxMin from "./maxmin";
import statisticToken, { merge as mergeToken } from "./statistic";
import useUniqueMemo from "../_util/hooks/useUniqueMemo";
import useDefaultCSP from "../hooks/useCSP";
function genStyleUtils(config) {
  // Dependency inversion for preparing basic config.
  var _config$useCSP = config.useCSP,
    useCSP = _config$useCSP === void 0 ? useDefaultCSP : _config$useCSP,
    useToken = config.useToken,
    usePrefix = config.usePrefix,
    getResetStyles = config.getResetStyles,
    getCommonStyle = config.getCommonStyle,
    getCompUnitless = config.getCompUnitless;
  function genStyleHooks(component, styleFn, getDefaultToken, options) {
    var componentName = Array.isArray(component) ? component[0] : component;
    function prefixToken(key) {
      return "".concat(String(componentName)).concat(key.slice(0, 1).toUpperCase()).concat(key.slice(1));
    }

    // Fill unitless
    var originUnitless = (options === null || options === void 0 ? void 0 : options.unitless) || {};
    var originCompUnitless = typeof getCompUnitless === 'function' ? getCompUnitless(component) : {};
    var compUnitless = _objectSpread(_objectSpread({}, originCompUnitless), {}, _defineProperty({}, prefixToken('zIndexPopup'), true));
    Object.keys(originUnitless).forEach(function (key) {
      compUnitless[prefixToken(key)] = originUnitless[key];
    });

    // Options
    var mergedOptions = _objectSpread(_objectSpread({}, options), {}, {
      unitless: compUnitless,
      prefixToken: prefixToken
    });

    // Hooks
    var useStyle = genComponentStyleHook(component, styleFn, getDefaultToken, mergedOptions);
    var useCSSVar = genCSSVarRegister(componentName, getDefaultToken, mergedOptions);
    return function (prefixCls) {
      var rootCls = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : prefixCls;
      var _useStyle = useStyle(prefixCls, rootCls),
        _useStyle2 = _slicedToArray(_useStyle, 2),
        hashId = _useStyle2[1];
      var _useCSSVar = useCSSVar(rootCls),
        _useCSSVar2 = _slicedToArray(_useCSSVar, 2),
        wrapCSSVar = _useCSSVar2[0],
        cssVarCls = _useCSSVar2[1];
      return [wrapCSSVar, hashId, cssVarCls];
    };
  }
  function genCSSVarRegister(component, getDefaultToken, options) {
    var compUnitless = options.unitless,
      _options$injectStyle = options.injectStyle,
      injectStyle = _options$injectStyle === void 0 ? true : _options$injectStyle,
      prefixToken = options.prefixToken,
      ignore = options.ignore;
    var CSSVarRegister = function CSSVarRegister(_ref) {
      var rootCls = _ref.rootCls,
        _ref$cssVar = _ref.cssVar,
        cssVar = _ref$cssVar === void 0 ? {} : _ref$cssVar;
      var _useToken = useToken(),
        realToken = _useToken.realToken;
      useCSSVarRegister({
        path: [component],
        prefix: cssVar.prefix,
        key: cssVar.key,
        unitless: compUnitless,
        ignore: ignore,
        token: realToken,
        scope: rootCls
      }, function () {
        var defaultToken = getDefaultComponentToken(component, realToken, getDefaultToken);
        var componentToken = getComponentToken(component, realToken, defaultToken, {
          deprecatedTokens: options === null || options === void 0 ? void 0 : options.deprecatedTokens
        });
        Object.keys(defaultToken).forEach(function (key) {
          componentToken[prefixToken(key)] = componentToken[key];
          delete componentToken[key];
        });
        return componentToken;
      });
      return null;
    };
    var useCSSVar = function useCSSVar(rootCls) {
      var _useToken2 = useToken(),
        cssVar = _useToken2.cssVar;
      return [function (node) {
        return injectStyle && cssVar ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CSSVarRegister, {
          rootCls: rootCls,
          cssVar: cssVar,
          component: component
        }), node) : node;
      }, cssVar === null || cssVar === void 0 ? void 0 : cssVar.key];
    };
    return useCSSVar;
  }
  function genComponentStyleHook(componentName, styleFn, getDefaultToken) {
    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    var cells = Array.isArray(componentName) ? componentName : [componentName, componentName];
    var _cells = _slicedToArray(cells, 1),
      component = _cells[0];
    var concatComponent = cells.join('-');
    var mergedLayer = config.layer || {
      name: 'antd'
    };

    // Return new style hook
    return function (prefixCls) {
      var rootCls = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : prefixCls;
      var _useToken3 = useToken(),
        theme = _useToken3.theme,
        realToken = _useToken3.realToken,
        hashId = _useToken3.hashId,
        token = _useToken3.token,
        cssVar = _useToken3.cssVar;
      var _usePrefix = usePrefix(),
        rootPrefixCls = _usePrefix.rootPrefixCls,
        iconPrefixCls = _usePrefix.iconPrefixCls;
      var csp = useCSP();
      var type = cssVar ? 'css' : 'js';

      // Use unique memo to share the result across all instances
      var calc = useUniqueMemo(function () {
        var unitlessCssVar = new Set();
        if (cssVar) {
          Object.keys(options.unitless || {}).forEach(function (key) {
            // Some component proxy the AliasToken (e.g. Image) and some not (e.g. Modal)
            // We should both pass in `unitlessCssVar` to make sure the CSSVar can be unitless.
            unitlessCssVar.add(token2CSSVar(key, cssVar.prefix));
            unitlessCssVar.add(token2CSSVar(key, getCompVarPrefix(component, cssVar.prefix)));
          });
        }
        return genCalc(type, unitlessCssVar);
      }, [type, component, cssVar === null || cssVar === void 0 ? void 0 : cssVar.prefix]);
      var _genMaxMin = genMaxMin(type),
        max = _genMaxMin.max,
        min = _genMaxMin.min;

      // Shared config
      var sharedConfig = {
        theme: theme,
        token: token,
        hashId: hashId,
        nonce: function nonce() {
          return csp.nonce;
        },
        clientOnly: options.clientOnly,
        layer: mergedLayer,
        // antd is always at top of styles
        order: options.order || -999
      };

      // This if statement is safe, as it will only be used if the generator has the function. It's not dynamic.
      if (typeof getResetStyles === 'function') {
        // Generate style for all need reset tags.
        useStyleRegister(_objectSpread(_objectSpread({}, sharedConfig), {}, {
          clientOnly: false,
          path: ['Shared', rootPrefixCls]
        }), function () {
          return getResetStyles(token, {
            prefix: {
              rootPrefixCls: rootPrefixCls,
              iconPrefixCls: iconPrefixCls
            },
            csp: csp
          });
        });
      }
      var wrapSSR = useStyleRegister(_objectSpread(_objectSpread({}, sharedConfig), {}, {
        path: [concatComponent, prefixCls, iconPrefixCls]
      }), function () {
        if (options.injectStyle === false) {
          return [];
        }
        var _statisticToken = statisticToken(token),
          proxyToken = _statisticToken.token,
          flush = _statisticToken.flush;
        var defaultComponentToken = getDefaultComponentToken(component, realToken, getDefaultToken);
        var componentCls = ".".concat(prefixCls);
        var componentToken = getComponentToken(component, realToken, defaultComponentToken, {
          deprecatedTokens: options.deprecatedTokens
        });
        if (cssVar && defaultComponentToken && _typeof(defaultComponentToken) === 'object') {
          Object.keys(defaultComponentToken).forEach(function (key) {
            defaultComponentToken[key] = "var(".concat(token2CSSVar(key, getCompVarPrefix(component, cssVar.prefix)), ")");
          });
        }
        var mergedToken = mergeToken(proxyToken, {
          componentCls: componentCls,
          prefixCls: prefixCls,
          iconCls: ".".concat(iconPrefixCls),
          antCls: ".".concat(rootPrefixCls),
          calc: calc,
          // @ts-ignore
          max: max,
          // @ts-ignore
          min: min
        }, cssVar ? defaultComponentToken : componentToken);
        var styleInterpolation = styleFn(mergedToken, {
          hashId: hashId,
          prefixCls: prefixCls,
          rootPrefixCls: rootPrefixCls,
          iconPrefixCls: iconPrefixCls
        });
        flush(component, componentToken);
        var commonStyle = typeof getCommonStyle === 'function' ? getCommonStyle(mergedToken, prefixCls, rootCls, options.resetFont) : null;
        return [options.resetStyle === false ? null : commonStyle, styleInterpolation];
      });
      return [wrapSSR, hashId];
    };
  }
  function genSubStyleComponent(componentName, styleFn, getDefaultToken) {
    var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    var useStyle = genComponentStyleHook(componentName, styleFn, getDefaultToken, _objectSpread({
      resetStyle: false,
      // Sub Style should default after root one
      order: -998
    }, options));
    var StyledComponent = function StyledComponent(_ref2) {
      var prefixCls = _ref2.prefixCls,
        _ref2$rootCls = _ref2.rootCls,
        rootCls = _ref2$rootCls === void 0 ? prefixCls : _ref2$rootCls;
      useStyle(prefixCls, rootCls);
      return null;
    };
    if (process.env.NODE_ENV !== 'production') {
      StyledComponent.displayName = "SubStyle_".concat(String(Array.isArray(componentName) ? componentName.join('.') : componentName));
    }
    return StyledComponent;
  }
  return {
    genStyleHooks: genStyleHooks,
    genSubStyleComponent: genSubStyleComponent,
    genComponentStyleHook: genComponentStyleHook
  };
}
export default genStyleUtils;