import { makeInner, normalizeToArray } from "../util/model.mjs";
import { keys, reduce, each, extend, hasOwn, indexOf, isArrayLike, bind, assert, eqNaN } from "../../../../../zrender@5.4.4/node_modules/zrender/lib/core/util.mjs";
import { cloneValue } from "../../../../../zrender@5.4.4/node_modules/zrender/lib/animation/Animator.mjs";
import Displayable from "../../../../../zrender@5.4.4/node_modules/zrender/lib/graphic/Displayable.mjs";
import { getAnimationConfig } from "./basicTransition.mjs";
import "../util/graphic.mjs";
import { warn } from "../util/log.mjs";
import { TRANSFORMABLE_PROPS } from "../../../../../zrender@5.4.4/node_modules/zrender/lib/core/Transformable.mjs";
import Path from "../../../../../zrender@5.4.4/node_modules/zrender/lib/graphic/Path.mjs";
var LEGACY_TRANSFORM_PROPS_MAP = {
  position: ["x", "y"],
  scale: ["scaleX", "scaleY"],
  origin: ["originX", "originY"]
};
var LEGACY_TRANSFORM_PROPS = keys(LEGACY_TRANSFORM_PROPS_MAP);
var TRANSFORM_PROPS_MAP = reduce(TRANSFORMABLE_PROPS, function(obj, key) {
  obj[key] = 1;
  return obj;
}, {});
var transformPropNamesStr = TRANSFORMABLE_PROPS.join(", ");
var ELEMENT_ANIMATABLE_PROPS = ["", "style", "shape", "extra"];
var transitionInnerStore = makeInner();
function getElementAnimationConfig(animationType, el, elOption, parentModel, dataIndex) {
  var animationProp = animationType + "Animation";
  var config = getAnimationConfig(animationType, parentModel, dataIndex) || {};
  var userDuring = transitionInnerStore(el).userDuring;
  if (config.duration > 0) {
    config.during = userDuring ? bind(duringCall, {
      el,
      userDuring
    }) : null;
    config.setToFinal = true;
    config.scope = animationType;
  }
  extend(config, elOption[animationProp]);
  return config;
}
function applyUpdateTransition(el, elOption, animatableModel, opts) {
  opts = opts || {};
  var dataIndex = opts.dataIndex, isInit = opts.isInit, clearStyle = opts.clearStyle;
  var hasAnimation = animatableModel.isAnimationEnabled();
  var store = transitionInnerStore(el);
  var styleOpt = elOption.style;
  store.userDuring = elOption.during;
  var transFromProps = {};
  var propsToSet = {};
  prepareTransformAllPropsFinal(el, elOption, propsToSet);
  prepareShapeOrExtraAllPropsFinal("shape", elOption, propsToSet);
  prepareShapeOrExtraAllPropsFinal("extra", elOption, propsToSet);
  if (!isInit && hasAnimation) {
    prepareTransformTransitionFrom(el, elOption, transFromProps);
    prepareShapeOrExtraTransitionFrom("shape", el, elOption, transFromProps);
    prepareShapeOrExtraTransitionFrom("extra", el, elOption, transFromProps);
    prepareStyleTransitionFrom(el, elOption, styleOpt, transFromProps);
  }
  propsToSet.style = styleOpt;
  applyPropsDirectly(el, propsToSet, clearStyle);
  applyMiscProps(el, elOption);
  if (hasAnimation) {
    if (isInit) {
      var enterFromProps_1 = {};
      each(ELEMENT_ANIMATABLE_PROPS, function(propName) {
        var prop = propName ? elOption[propName] : elOption;
        if (prop && prop.enterFrom) {
          if (propName) {
            enterFromProps_1[propName] = enterFromProps_1[propName] || {};
          }
          extend(propName ? enterFromProps_1[propName] : enterFromProps_1, prop.enterFrom);
        }
      });
      var config = getElementAnimationConfig("enter", el, elOption, animatableModel, dataIndex);
      if (config.duration > 0) {
        el.animateFrom(enterFromProps_1, config);
      }
    } else {
      applyPropsTransition(el, elOption, dataIndex || 0, animatableModel, transFromProps);
    }
  }
  updateLeaveTo(el, elOption);
  styleOpt ? el.dirty() : el.markRedraw();
}
function updateLeaveTo(el, elOption) {
  var leaveToProps = transitionInnerStore(el).leaveToProps;
  for (var i = 0; i < ELEMENT_ANIMATABLE_PROPS.length; i++) {
    var propName = ELEMENT_ANIMATABLE_PROPS[i];
    var prop = propName ? elOption[propName] : elOption;
    if (prop && prop.leaveTo) {
      if (!leaveToProps) {
        leaveToProps = transitionInnerStore(el).leaveToProps = {};
      }
      if (propName) {
        leaveToProps[propName] = leaveToProps[propName] || {};
      }
      extend(propName ? leaveToProps[propName] : leaveToProps, prop.leaveTo);
    }
  }
}
function applyLeaveTransition(el, elOption, animatableModel, onRemove) {
  if (el) {
    var parent_1 = el.parent;
    var leaveToProps = transitionInnerStore(el).leaveToProps;
    if (leaveToProps) {
      var config = getElementAnimationConfig("update", el, elOption, animatableModel, 0);
      config.done = function() {
        parent_1.remove(el);
        onRemove && onRemove();
      };
      el.animateTo(leaveToProps, config);
    } else {
      parent_1.remove(el);
      onRemove && onRemove();
    }
  }
}
function isTransitionAll(transition) {
  return transition === "all";
}
function applyPropsDirectly(el, allPropsFinal, clearStyle) {
  var styleOpt = allPropsFinal.style;
  if (!el.isGroup && styleOpt) {
    if (clearStyle) {
      el.useStyle({});
      var animators = el.animators;
      for (var i = 0; i < animators.length; i++) {
        var animator = animators[i];
        if (animator.targetName === "style") {
          animator.changeTarget(el.style);
        }
      }
    }
    el.setStyle(styleOpt);
  }
  if (allPropsFinal) {
    allPropsFinal.style = null;
    allPropsFinal && el.attr(allPropsFinal);
    allPropsFinal.style = styleOpt;
  }
}
function applyPropsTransition(el, elOption, dataIndex, model, transFromProps) {
  if (transFromProps) {
    var config = getElementAnimationConfig("update", el, elOption, model, dataIndex);
    if (config.duration > 0) {
      el.animateFrom(transFromProps, config);
    }
  }
}
function applyMiscProps(el, elOption) {
  hasOwn(elOption, "silent") && (el.silent = elOption.silent);
  hasOwn(elOption, "ignore") && (el.ignore = elOption.ignore);
  if (el instanceof Displayable) {
    hasOwn(elOption, "invisible") && (el.invisible = elOption.invisible);
  }
  if (el instanceof Path) {
    hasOwn(elOption, "autoBatch") && (el.autoBatch = elOption.autoBatch);
  }
}
var tmpDuringScope = {};
var transitionDuringAPI = {
  // Usually other props do not need to be changed in animation during.
  setTransform: function(key, val) {
    if (process.env.NODE_ENV !== "production") {
      assert(hasOwn(TRANSFORM_PROPS_MAP, key), "Only " + transformPropNamesStr + " available in `setTransform`.");
    }
    tmpDuringScope.el[key] = val;
    return this;
  },
  getTransform: function(key) {
    if (process.env.NODE_ENV !== "production") {
      assert(hasOwn(TRANSFORM_PROPS_MAP, key), "Only " + transformPropNamesStr + " available in `getTransform`.");
    }
    return tmpDuringScope.el[key];
  },
  setShape: function(key, val) {
    if (process.env.NODE_ENV !== "production") {
      assertNotReserved(key);
    }
    var el = tmpDuringScope.el;
    var shape = el.shape || (el.shape = {});
    shape[key] = val;
    el.dirtyShape && el.dirtyShape();
    return this;
  },
  getShape: function(key) {
    if (process.env.NODE_ENV !== "production") {
      assertNotReserved(key);
    }
    var shape = tmpDuringScope.el.shape;
    if (shape) {
      return shape[key];
    }
  },
  setStyle: function(key, val) {
    if (process.env.NODE_ENV !== "production") {
      assertNotReserved(key);
    }
    var el = tmpDuringScope.el;
    var style = el.style;
    if (style) {
      if (process.env.NODE_ENV !== "production") {
        if (eqNaN(val)) {
          warn("style." + key + " must not be assigned with NaN.");
        }
      }
      style[key] = val;
      el.dirtyStyle && el.dirtyStyle();
    }
    return this;
  },
  getStyle: function(key) {
    if (process.env.NODE_ENV !== "production") {
      assertNotReserved(key);
    }
    var style = tmpDuringScope.el.style;
    if (style) {
      return style[key];
    }
  },
  setExtra: function(key, val) {
    if (process.env.NODE_ENV !== "production") {
      assertNotReserved(key);
    }
    var extra = tmpDuringScope.el.extra || (tmpDuringScope.el.extra = {});
    extra[key] = val;
    return this;
  },
  getExtra: function(key) {
    if (process.env.NODE_ENV !== "production") {
      assertNotReserved(key);
    }
    var extra = tmpDuringScope.el.extra;
    if (extra) {
      return extra[key];
    }
  }
};
function assertNotReserved(key) {
  if (process.env.NODE_ENV !== "production") {
    if (key === "transition" || key === "enterFrom" || key === "leaveTo") {
      throw new Error('key must not be "' + key + '"');
    }
  }
}
function duringCall() {
  var scope = this;
  var el = scope.el;
  if (!el) {
    return;
  }
  var latestUserDuring = transitionInnerStore(el).userDuring;
  var scopeUserDuring = scope.userDuring;
  if (latestUserDuring !== scopeUserDuring) {
    scope.el = scope.userDuring = null;
    return;
  }
  tmpDuringScope.el = el;
  scopeUserDuring(transitionDuringAPI);
}
function prepareShapeOrExtraTransitionFrom(mainAttr, fromEl, elOption, transFromProps) {
  var attrOpt = elOption[mainAttr];
  if (!attrOpt) {
    return;
  }
  var elPropsInAttr = fromEl[mainAttr];
  var transFromPropsInAttr;
  if (elPropsInAttr) {
    var transition = elOption.transition;
    var attrTransition = attrOpt.transition;
    if (attrTransition) {
      !transFromPropsInAttr && (transFromPropsInAttr = transFromProps[mainAttr] = {});
      if (isTransitionAll(attrTransition)) {
        extend(transFromPropsInAttr, elPropsInAttr);
      } else {
        var transitionKeys = normalizeToArray(attrTransition);
        for (var i = 0; i < transitionKeys.length; i++) {
          var key = transitionKeys[i];
          var elVal = elPropsInAttr[key];
          transFromPropsInAttr[key] = elVal;
        }
      }
    } else if (isTransitionAll(transition) || indexOf(transition, mainAttr) >= 0) {
      !transFromPropsInAttr && (transFromPropsInAttr = transFromProps[mainAttr] = {});
      var elPropsInAttrKeys = keys(elPropsInAttr);
      for (var i = 0; i < elPropsInAttrKeys.length; i++) {
        var key = elPropsInAttrKeys[i];
        var elVal = elPropsInAttr[key];
        if (isNonStyleTransitionEnabled(attrOpt[key], elVal)) {
          transFromPropsInAttr[key] = elVal;
        }
      }
    }
  }
}
function prepareShapeOrExtraAllPropsFinal(mainAttr, elOption, allProps) {
  var attrOpt = elOption[mainAttr];
  if (!attrOpt) {
    return;
  }
  var allPropsInAttr = allProps[mainAttr] = {};
  var keysInAttr = keys(attrOpt);
  for (var i = 0; i < keysInAttr.length; i++) {
    var key = keysInAttr[i];
    allPropsInAttr[key] = cloneValue(attrOpt[key]);
  }
}
function prepareTransformTransitionFrom(el, elOption, transFromProps) {
  var transition = elOption.transition;
  var transitionKeys = isTransitionAll(transition) ? TRANSFORMABLE_PROPS : normalizeToArray(transition || []);
  for (var i = 0; i < transitionKeys.length; i++) {
    var key = transitionKeys[i];
    if (key === "style" || key === "shape" || key === "extra") {
      continue;
    }
    var elVal = el[key];
    if (process.env.NODE_ENV !== "production") {
      checkTransformPropRefer(key, "el.transition");
    }
    transFromProps[key] = elVal;
  }
}
function prepareTransformAllPropsFinal(el, elOption, allProps) {
  for (var i = 0; i < LEGACY_TRANSFORM_PROPS.length; i++) {
    var legacyName = LEGACY_TRANSFORM_PROPS[i];
    var xyName = LEGACY_TRANSFORM_PROPS_MAP[legacyName];
    var legacyArr = elOption[legacyName];
    if (legacyArr) {
      allProps[xyName[0]] = legacyArr[0];
      allProps[xyName[1]] = legacyArr[1];
    }
  }
  for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) {
    var key = TRANSFORMABLE_PROPS[i];
    if (elOption[key] != null) {
      allProps[key] = elOption[key];
    }
  }
}
function prepareStyleTransitionFrom(fromEl, elOption, styleOpt, transFromProps) {
  if (!styleOpt) {
    return;
  }
  var fromElStyle = fromEl.style;
  var transFromStyleProps;
  if (fromElStyle) {
    var styleTransition = styleOpt.transition;
    var elTransition = elOption.transition;
    if (styleTransition && !isTransitionAll(styleTransition)) {
      var transitionKeys = normalizeToArray(styleTransition);
      !transFromStyleProps && (transFromStyleProps = transFromProps.style = {});
      for (var i = 0; i < transitionKeys.length; i++) {
        var key = transitionKeys[i];
        var elVal = fromElStyle[key];
        transFromStyleProps[key] = elVal;
      }
    } else if (fromEl.getAnimationStyleProps && (isTransitionAll(elTransition) || isTransitionAll(styleTransition) || indexOf(elTransition, "style") >= 0)) {
      var animationProps = fromEl.getAnimationStyleProps();
      var animationStyleProps = animationProps ? animationProps.style : null;
      if (animationStyleProps) {
        !transFromStyleProps && (transFromStyleProps = transFromProps.style = {});
        var styleKeys = keys(styleOpt);
        for (var i = 0; i < styleKeys.length; i++) {
          var key = styleKeys[i];
          if (animationStyleProps[key]) {
            var elVal = fromElStyle[key];
            transFromStyleProps[key] = elVal;
          }
        }
      }
    }
  }
}
function isNonStyleTransitionEnabled(optVal, elVal) {
  return !isArrayLike(optVal) ? optVal != null && isFinite(optVal) : optVal !== elVal;
}
var checkTransformPropRefer;
if (process.env.NODE_ENV !== "production") {
  checkTransformPropRefer = function(key, usedIn) {
    if (!hasOwn(TRANSFORM_PROPS_MAP, key)) {
      warn("Prop `" + key + "` is not a permitted in `" + usedIn + "`. Only `" + keys(TRANSFORM_PROPS_MAP).join("`, `") + "` are permitted.");
    }
  };
}
export {
  ELEMENT_ANIMATABLE_PROPS,
  applyLeaveTransition,
  applyUpdateTransition,
  isTransitionAll,
  updateLeaveTo
};
