import type { AnimationOptions } from '@/common/interfaces'
import { Container, Sprite, Texture, Ticker } from 'pixi.js'
import { Tile } from './Tile'

export abstract class SpriteBase {
  private _interactive: boolean = false
  protected sprite: Sprite = new Sprite()
  private container?: Container

  constructor(
    protected ticker?: Ticker,
    protected scale: number = 1
  ) {
    this.ticker = ticker
    this.scale = scale
  }

  abstract createTexture(): Texture

  set interactive(value: boolean) {
    this._interactive = value
    this.sprite.eventMode = value ? 'static' : 'none'
    this.sprite.cursor = value ? 'pointer' : 'default'
  }

  get interactive(): boolean {
    return this._interactive
  }

  get x(): number {
    return this.sprite.x
  }

  get y(): number {
    return this.sprite.y
  }

  get width(): number {
    return this.sprite.width
  }

  get height(): number {
    return this.sprite.height
  }

  set alpha(value: number) {
    this.sprite.alpha = value
  }

  get alpha(): number {
    return this.sprite.alpha
  }

  set anchor(value: { x: number; y: number } | number) {
    if (typeof value === 'number') {
      this.sprite.anchor.set(value)
      return
    }
    this.sprite.anchor.set(value.x, value.y)
  }

  on(event: string, fn: any): void {
    this.sprite.on(event, fn)
  }

  off(event: string): void {
    this.sprite.off(event)
  }

  getSprite(): Sprite {
    return this.sprite
  }

  setPosition(x: number, y: number) {
    this.sprite.x = x
    this.sprite.y = y
  }

  setFilters(filters: any[]) {
    this.sprite.filters = filters
  }

  clearFilters() {
    this.sprite.filters = []
  }

  animateTo(options: AnimationOptions): Promise<void> {
    return new Promise((resolve) => {
      const {
        x: targetX,
        y: targetY,
        rotation: targetRotation,
        duration = 10,
        width: targetWidth,
        height: targetHeight
      } = options

      const initialX = this.sprite.x
      const initialY = this.sprite.y
      const initialRotation = this.sprite.rotation
      const initialWidth = this.sprite.width
      const initialHeight = this.sprite.height

      const deltaX = targetX ? targetX - this.sprite.x : null
      const deltaY = targetY ? targetY - this.sprite.y : null
      const deltaRotation = targetRotation ? targetRotation - this.sprite.rotation : null
      const deltaWidth = targetWidth ? targetWidth - this.sprite.width : null
      const deltaHeight = targetHeight ? targetHeight - this.sprite.height : null

      let elapsed: number = 0

      const tick: any = (delta: any) => {
        elapsed += delta.deltaTime
        const progress = Math.min(elapsed / duration, 1)

        // Linear interpolation
        if (deltaX !== null) this.sprite.x = initialX + deltaX * progress
        if (deltaY !== null) this.sprite.y = initialY + deltaY * progress

        // Rotation interpolation
        if (deltaRotation !== null)
          this.sprite.rotation = initialRotation + deltaRotation * progress

        // Scale interpolation
        // this.sprite.width = initialWidth + deltaWidth * progress
        // this.sprite.height = initialHeight + deltaHeight * progress

        //
        if (progress === 1) {
          this.ticker?.remove(tick)
          resolve()
        }
      }

      this.ticker?.add(tick)
    })
  }

  addTo(container: any) {
    this.container = container
    container.addChild(this.sprite)
  }

  removeFromParent() {
    this.container?.removeChild(this.sprite)
  }
}
