/**
 * Developer: Molla Samser
 * Organization: RSK World
 * Website: https://rskworld.in
 * Email: hello@rskworld.in, support@rskworld.in
 * Phone: +91 93305 39277
 * Address: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India, 713147
 * Copyright © 2026 RSK World. All rights reserved.
 */

class Sprite {
  constructor({
    position,
    imageSrc,
    scale = 1,
    framesMax = 1,
    offset = { x: 0, y: 0 },
    offsetY = 0,
    rows = 1,
    maxFrames = 1,
    repeat = false
  }) {
    this.position = position
    this.image = new Image()
    this.image.src = imageSrc
    this.scale = scale
    this.framesMax = framesMax
    this.maxFrames = maxFrames || framesMax
    this.framesCurrent = 0
    this.framesElapsed = 0
    this.framesHold = 5
    this.offset = offset
    this.offsetY = offsetY
    this.rows = rows
    this.repeat = repeat
    
    this.width = 50
    this.height = 150
  }

  draw() {
    const frameWidth = this.image.width / this.maxFrames
    const frameHeight = this.image.height / this.rows
    
    const drawX = this.position.x - this.offset.x
    const drawY = this.position.y - this.offset.y
    const targetWidth = frameWidth * this.scale
    const targetHeight = frameHeight * this.scale

    c.drawImage(
      this.image,
      this.framesCurrent * frameWidth,
      this.offsetY,
      frameWidth,
      frameHeight,
      drawX,
      drawY,
      targetWidth,
      targetHeight
    )

    // If repeat is enabled, draw a second copy to fill gaps
    if (this.repeat && drawX < 0) {
        c.drawImage(
          this.image,
          this.framesCurrent * frameWidth,
          this.offsetY,
          frameWidth,
          frameHeight,
          drawX + targetWidth,
          drawY,
          targetWidth,
          targetHeight
        )
    }
  }

  animateFrames() {
    this.framesElapsed++

    if (this.framesElapsed % this.framesHold === 0) {
      if (this.framesCurrent < this.framesMax - 1) {
        this.framesCurrent++
      } else {
        this.framesCurrent = 0
      }
    }
  }

  update() {
    this.draw()
    this.animateFrames()
  }
}

class Fighter extends Sprite {
  constructor({
    position,
    velocity,
    color = 'red',
    imageSrc,
    scale = 1,
    framesMax = 1,
    offset = { x: 0, y: 0 },
    offsetY = 0,
    rows = 1,
    maxFrames = 1,
    sprites,
    attackBox = { offset: {}, width: undefined, height: undefined },
    sounds = {}
  }) {
    super({
      position,
      imageSrc,
      scale,
      framesMax,
      offset,
      offsetY,
      rows,
      maxFrames
    })

    this.velocity = velocity
    this.lastKey
    this.attackBox = {
      position: {
        x: this.position.x,
        y: this.position.y
      },
      offset: attackBox.offset,
      width: attackBox.width,
      height: attackBox.height
    }
    this.color = color
    this.isAttacking
    this.health = 100
    this.framesCurrent = 0
    this.framesElapsed = 0
    this.framesHold = 5
    this.sprites = sprites
    this.dead = false
    this.sounds = sounds
    this.mana = 0
    this.combo = 0
    this.comboTimeout = null
    this.isSpecialAttacking = false

    for (const sprite in this.sprites) {
      sprites[sprite].image = new Image()
      sprites[sprite].image.src = sprites[sprite].imageSrc
      if (!sprites[sprite].offsetY) sprites[sprite].offsetY = 0
    }
  }

  draw() {
    const frameWidth = this.image.width / this.maxFrames
    const frameHeight = this.image.height / this.rows
    
    // Hitbox logic
    this.width = 60 
    this.height = 150

    c.drawImage(
      this.image,
      this.framesCurrent * frameWidth,
      this.offsetY,
      frameWidth,
      frameHeight,
      this.position.x - this.offset.x,
      this.position.y - this.offset.y,
      frameWidth * this.scale,
      frameHeight * this.scale
    )
  }

  update() {
    this.draw()
    if (!this.dead) this.animateFrames()

    // attack boxes
    this.attackBox.position.x = this.position.x + this.attackBox.offset.x
    this.attackBox.position.y = this.position.y + this.attackBox.offset.y

    this.position.x += this.velocity.x
    this.position.y += this.velocity.y

    // gravity function
    const groundLevel = canvas.height - 96
    if (this.position.y + this.height + this.velocity.y >= groundLevel) {
      this.velocity.y = 0
      this.position.y = groundLevel - this.height
    } else this.velocity.y += gravity
  }

  attack() {
    this.switchSprite('attack1')
    this.isAttacking = true
    if (this.sounds.attack) {
      this.sounds.attack.currentTime = 0
      this.sounds.attack.play().catch(e => {})
    }
  }

  specialAttack() {
    if (this.mana < 100 || this.dead) return
    
    this.isSpecialAttacking = true
    this.switchSprite('specialAttack')
    this.mana = 0
    
    if (this.sounds.attack) {
      this.sounds.attack.currentTime = 0
      this.sounds.attack.play().catch(e => {})
    }
  }

  updateCombo() {
    this.combo++
    if (this.comboTimeout) clearTimeout(this.comboTimeout)
    this.comboTimeout = setTimeout(() => {
      this.combo = 0
    }, 1000)
  }

  takeHit(damage = 20) {
    this.health -= damage
    if (this.health < 0) this.health = 0

    this.mana += 15
    if (this.mana > 100) this.mana = 100
    
    this.combo = 0
    
    if (this.sounds.hit) {
      this.sounds.hit.currentTime = 0
      this.sounds.hit.play().catch(e => {})
    }

    if (this.health <= 0) {
      this.switchSprite('death')
    } else this.switchSprite('takeHit')
  }

  switchSprite(sprite) {
    if (this.image === this.sprites.death.image) {
      if (this.framesCurrent === this.sprites.death.framesMax - 1)
        this.dead = true
      return
    }

    if (
      this.image === this.sprites.attack1.image &&
      this.framesCurrent < this.sprites.attack1.framesMax - 1
    )
      return

    if (
      this.sprites.specialAttack &&
      this.image === this.sprites.specialAttack.image &&
      this.framesCurrent < this.sprites.specialAttack.framesMax - 1
    )
      return

    if (
      this.image === this.sprites.takeHit.image &&
      this.framesCurrent < this.sprites.takeHit.framesMax - 1
    )
      return

    switch (sprite) {
      case 'idle':
        if (this.image !== this.sprites.idle.image) {
          this.image = this.sprites.idle.image
          this.framesMax = this.sprites.idle.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.idle.offsetY || 0
        }
        break
      case 'run':
        if (this.image !== this.sprites.run.image) {
          this.image = this.sprites.run.image
          this.framesMax = this.sprites.run.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.run.offsetY || 0
        }
        break
      case 'jump':
        if (this.image !== this.sprites.jump.image) {
          this.image = this.sprites.jump.image
          this.framesMax = this.sprites.jump.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.jump.offsetY || 0
        }
        break

      case 'fall':
        if (this.image !== this.sprites.fall.image) {
          this.image = this.sprites.fall.image
          this.framesMax = this.sprites.fall.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.fall.offsetY || 0
        }
        break

      case 'attack1':
        if (this.image !== this.sprites.attack1.image) {
          this.image = this.sprites.attack1.image
          this.framesMax = this.sprites.attack1.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.attack1.offsetY || 0
        }
        break

      case 'takeHit':
        if (this.image !== this.sprites.takeHit.image) {
          this.image = this.sprites.takeHit.image
          this.framesMax = this.sprites.takeHit.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.takeHit.offsetY || 0
        }
        break

      case 'specialAttack':
        if (this.sprites.specialAttack && this.image !== this.sprites.specialAttack.image) {
          this.image = this.sprites.specialAttack.image
          this.framesMax = this.sprites.specialAttack.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.specialAttack.offsetY
        }
        break

      case 'death':
        if (this.image !== this.sprites.death.image) {
          this.image = this.sprites.death.image
          this.framesMax = this.sprites.death.framesMax
          this.framesCurrent = 0
          this.offsetY = this.sprites.death.offsetY
        }
        break
    }
  }
}
