class Tween {
  constructor(target, duration, easing = 'linear') {
    this.target = target;
    this.duration = duration;
    this.easing = this.getEasingFunction(easing);
    this.startTime = null;
    this.startValues = {};
    this.endValues = {};
    this.onUpdate = null;
    this.onComplete = null;
    this.onRepeat = null;
    this.delayTime = 0;
    this.repeatCount = 0;
    this.yoyo = false;
    this.isYoyoBack = false;
    this.isPaused = false;
    this.isReversed = false;
    this.progress = 0;
  }

  to(properties) {
    // 记录起始值
    for (let prop in properties) {
      if (typeof this.target[prop] === 'number') {
        this.startValues[prop] = this.target[prop];
      } else if (this.target.element && this.target.element.style) {
        // 对于CSS属性，需要特殊处理
        const style = getComputedStyle(this.target.element);
        if (prop === 'opacity') {
          this.startValues[prop] = parseFloat(style[prop]) || 1;
        } else if (prop === 'scale') {
          // 处理缩放
          const transform = style.transform;
          const scaleMatch = transform.match(/scale\(([^)]+)\)/);
          this.startValues[prop] = scaleMatch ? parseFloat(scaleMatch[1]) : 1;
        } else if (prop === 'rotate') {
          // 处理旋转
          const transform = style.transform;
          const rotateMatch = transform.match(/rotate\(([^)]+)deg\)/);
          this.startValues[prop] = rotateMatch ? parseFloat(rotateMatch[1]) : 0;
        } else {
          this.startValues[prop] = parseFloat(style[prop]) || 0;
        }
      }
    }
    
    this.endValues = properties;
    return this;
  }

  from(properties) {
    // 从指定值开始动画
    for (let prop in properties) {
      if (typeof this.target[prop] === 'number') {
        this.startValues[prop] = properties[prop];
        // 设置目标对象的初始值
        this.target[prop] = properties[prop];
      } else if (this.target.element && this.target.element.style) {
        // 对于CSS属性，设置初始样式
        if (prop === 'opacity') {
          this.startValues[prop] = properties[prop];
          this.target.element.style[prop] = properties[prop];
        } else if (prop === 'scale') {
          this.startValues[prop] = properties[prop];
          this.target.element.style.transform = `scale(${properties[prop]})`;
        } else if (prop === 'rotate') {
          this.startValues[prop] = properties[prop];
          this.target.element.style.transform = `rotate(${properties[prop]}deg)`;
        } else {
          this.startValues[prop] = properties[prop];
          this.target.element.style[prop] = `${properties[prop]}px`;
        }
      }
    }
    return this;
  }

  delay(time) {
    this.delayTime = time;
    return this;
  }

  repeat(count) {
    this.repeatCount = count;
    return this;
  }

  yoyo(enable = true) {
    this.yoyo = enable;
    return this;
  }

  reverse() {
    this.isReversed = !this.isReversed;
    return this;
  }

  pause() {
    this.isPaused = true;
    return this;
  }

  resume() {
    if (this.isPaused) {
      this.isPaused = false;
      this.startTime = performance.now() - this.progress * this.duration;
      this.animate();
    }
    return this;
  }

  stop() {
    this.startTime = null;
    return this;
  }

  start() {
    if (this.delayTime > 0) {
      setTimeout(() => {
        this._startAnimation();
      }, this.delayTime);
    } else {
      this._startAnimation();
    }
    return this;
  }

  _startAnimation() {
    this.startTime = performance.now();
    this.isPaused = false;
    this.isReversed = false;
    this.isYoyoBack = false;
    this.animate();
    return this;
  }

  animate() {
    if (this.isPaused || !this.startTime) return;

    const now = performance.now();
    const elapsed = now - this.startTime;
    let progress = Math.min(elapsed / this.duration, 1);
    
    // 如果是反向播放
    if (this.isReversed) {
      progress = 1 - progress;
    }
    
    // 如果是yoyo回放
    if (this.yoyo && this.isYoyoBack) {
      progress = 1 - progress;
    }
    
    this.progress = progress;
    const easedProgress = this.easing(progress);

    // 更新属性值
    for (let prop in this.endValues) {
      const start = this.startValues[prop];
      const end = this.endValues[prop];
      const value = start + (end - start) * easedProgress;
      
      if (typeof this.target[prop] === 'number') {
        this.target[prop] = value;
      } else if (this.target.element && this.target.element.style) {
        // 处理CSS属性
        if (prop === 'opacity') {
          this.target.element.style[prop] = value;
        } else if (prop === 'scale') {
          // 处理缩放
          const currentTransform = this.target.element.style.transform || '';
          // 移除旧的scale
          const newTransform = currentTransform.replace(/scale\([^)]+\)/, '') + ` scale(${value})`;
          this.target.element.style.transform = newTransform;
        } else if (prop === 'rotate') {
          // 处理旋转
          const currentTransform = this.target.element.style.transform || '';
          // 移除旧的rotate
          const newTransform = currentTransform.replace(/rotate\([^)]+\)/, '') + ` rotate(${value}deg)`;
          this.target.element.style.transform = newTransform;
        } else {
          this.target.element.style[prop] = `${value}px`;
        }
      }
    }

    if (this.onUpdate) {
      this.onUpdate(easedProgress, this.target);
    }

    if (progress < 1) {
      requestAnimationFrame(() => this.animate());
    } else {
      // 动画完成
      if (this.repeatCount > 0) {
        // 需要重复
        this.repeatCount--;
        if (this.yoyo) {
          this.isYoyoBack = !this.isYoyoBack;
        }
        this.startTime = performance.now();
        if (this.onRepeat) {
          this.onRepeat();
        }
        requestAnimationFrame(() => this.animate());
      } else if (this.repeatCount === -1) {
        // 无限重复
        if (this.yoyo) {
          this.isYoyoBack = !this.isYoyoBack;
        }
        this.startTime = performance.now();
        if (this.onRepeat) {
          this.onRepeat();
        }
        requestAnimationFrame(() => this.animate());
      } else {
        // 真正完成
        if (this.onComplete) {
          this.onComplete(this.target);
        }
      }
    }
  }

  onUpdate(callback) {
    this.onUpdate = callback;
    return this;
  }

  onComplete(callback) {
    this.onComplete = callback;
    return this;
  }

  onRepeat(callback) {
    this.onRepeat = callback;
    return this;
  }

  chain(...tweens) {
    // 链式动画
    if (this.onComplete) {
      const originalComplete = this.onComplete;
      this.onComplete = (target) => {
        originalComplete(target);
        tweens.forEach(tween => tween.start());
      };
    } else {
      this.onComplete = () => {
        tweens.forEach(tween => tween.start());
      };
    }
    return this;
  }

  getEasingFunction(name) {
    const easings = {
      linear: t => t,
      easeInQuad: t => t * t,
      easeOutQuad: t => t * (2 - t),
      easeInOutQuad: t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
      easeInCubic: t => t * t * t,
      easeOutCubic: t => (--t) * t * t + 1,
      easeInOutCubic: t => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
      easeInQuart: t => t * t * t * t,
      easeOutQuart: t => 1 - (--t) * t * t * t,
      easeInOutQuart: t => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t,
      easeInQuint: t => t * t * t * t * t,
      easeOutQuint: t => 1 + (--t) * t * t * t * t,
      easeInOutQuint: t => t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t,
      easeInSine: t => 1 - Math.cos(t * Math.PI / 2),
      easeOutSine: t => Math.sin(t * Math.PI / 2),
      easeInOutSine: t => -(Math.cos(Math.PI * t) - 1) / 2,
      easeInExpo: t => t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
      easeOutExpo: t => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
      easeInOutExpo: t => {
        if (t === 0) return 0;
        if (t === 1) return 1;
        if (t < 0.5) return Math.pow(2, 20 * t - 10) / 2;
        return (2 - Math.pow(2, -20 * t + 10)) / 2;
      },
      easeInCirc: t => 1 - Math.sqrt(1 - t * t),
      easeOutCirc: t => Math.sqrt(1 - (--t) * t),
      easeInOutCirc: t => {
        if (t < 0.5) return (1 - Math.sqrt(1 - 4 * t * t)) / 2;
        return (Math.sqrt(1 - 4 * (--t) * t) + 1) / 2;
      },
      easeInBack: t => {
        const s = 1.70158;
        return t * t * ((s + 1) * t - s);
      },
      easeOutBack: t => {
        const s = 1.70158;
        return --t * t * ((s + 1) * t + s) + 1;
      },
      easeInOutBack: t => {
        const s = 1.70158 * 1.525;
        if (t < 0.5) return (t * t * (2 * t * s + 2 * t - s)) / 2;
        return (2 * (t - 1) * (t - 1) * (2 * (t - 1) * s + 2 * (t - 1) + s) + 2) / 2;
      },
      easeInElastic: t => {
        if (t === 0) return 0;
        if (t === 1) return 1;
        return -Math.pow(2, 10 * (t - 1)) * Math.sin((t - 1.1) * 5 * Math.PI);
      },
      easeOutElastic: t => {
        if (t === 0) return 0;
        if (t === 1) return 1;
        return Math.pow(2, -10 * t) * Math.sin((t - 0.1) * 5 * Math.PI) + 1;
      },
      easeInOutElastic: t => {
        if (t === 0) return 0;
        if (t === 1) return 1;
        if (t < 0.5) return -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * Math.PI / 4.5)) / 2;
        return Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * Math.PI / 4.5) / 2 + 1;
      },
      easeInBounce: t => 1 - this.getEasingFunction('easeOutBounce')(1 - t),
      easeOutBounce: t => {
        const n1 = 7.5625;
        const d1 = 2.75;
        if (t < 1 / d1) {
          return n1 * t * t;
        } else if (t < 2 / d1) {
          return n1 * (t -= 1.5 / d1) * t + 0.75;
        } else if (t < 2.5 / d1) {
          return n1 * (t -= 2.25 / d1) * t + 0.9375;
        } else {
          return n1 * (t -= 2.625 / d1) * t + 0.984375;
        }
      },
      easeInOutBounce: t => {
        if (t < 0.5) return (1 - this.getEasingFunction('easeOutBounce')(1 - 2 * t)) / 2;
        return (1 + this.getEasingFunction('easeOutBounce')(2 * t - 1)) / 2;
      }
    };
    
    return easings[name] || easings.linear;
  }
}

export default Tween;
export { Tween };