import { LoggingService } from '@/services/LoggingService'
import { Application, Container, Graphics, Sprite, Texture } from 'pixi.js'
import { Scale, type ScaleFunction } from './utilities/scale'
import { Tile } from './Tile'
import type { Movement, PlayerDto, TileDto } from '@/common/interfaces'
import { createContainer } from '@/common/helpers'
import { createText, playerNameText, whiteStyle } from './utilities/fonts'
import Config from '@/game/Config'

export class OtherHand {
  tilesInitialNumber: number = 7
  player?: PlayerDto
  hand: Tile[] = []
  container: Container = new Container()
  height: number
  width: number
  scale: number = 0.5
  scaleY!: ScaleFunction
  scaleX!: ScaleFunction
  x: number = 0
  y: number = 0
  grain: number = 25
  logger: LoggingService = new LoggingService()
  tilesLayer!: Container
  interactionsLayer!: Container
  scoreLayer: Container = new Container()
  score: number = 0
  active: boolean = false

  constructor(
    private app: Application,
    public position: 'left' | 'right' | 'top' = 'left',
  ) {
    this.height = 100
    this.width = 300
    app.stage.addChild(this.container)
    const { x, y } = this.getPosition()
    this.container.width = this.width
    this.container.height = this.height
    this.container.x = x
    this.container.y = y
    this.calculateScale()
    this.initLayers()
    this.render()
  }

  setPlayer(player: PlayerDto) {
    this.player = player
    this.container.addChild(
      createText({
        text: `${player.name}`,
        x: this.width / 2,
        y: 12,
        style: playerNameText,
      }),
    )
  }

  setActive(active: boolean) {
    this.active = active
    this.render()
  }

  setScore(score: number) {
    this.score = score
    this.render()
  }

  setHand(tiles: TileDto[]) {
    this.hand = tiles.map((tile) => new Tile(tile.id, this.app.ticker, tile.pips, this.scale))
    this.render()
  }

  update(move: Movement) {
    this.hand = this.hand.filter((tile) => tile.id !== move?.tile?.id)
    this.render()
  }

  private renderScore() {
    this.scoreLayer.removeChildren()
    const text = createText({
      text: `${this.score}`,
      x: this.width - 5,
      y: 50,
      style: whiteStyle(36, 'bold'),
    })
    text.anchor.set(1, 0.5)
    this.scoreLayer.addChild(text)
  }

  private renderTiles() {
    this.tilesLayer.removeChildren()
    const x = -9
    this.hand.forEach((tile, index) => {
      tile.setPosition(this.scaleX(x + index * 2), this.height / 2 + 10)
      this.tilesLayer.addChild(tile.getSprite())
    })
  }

  private renderActive() {
    this.interactionsLayer.removeChildren()
    if (this.active) {
      const rectangle = new Graphics()
        .roundRect(0, 0, this.width, this.height, 5)
        .stroke(Config.activeHandStrokeColor)
      this.interactionsLayer.addChild(rectangle)
    }
  }

  private render() {
    this.renderTiles()
    this.renderScore()
    this.renderActive()
  }

  private addBg() {
    const bg = new Sprite(Texture.WHITE)
    bg.alpha = 0.08
    bg.width = this.width
    bg.height = this.height
    this.container.addChild(bg)
  }

  private getPosition() {
    let x = 0
    let y = 0

    if (this.position === 'left') {
      x = 16
      y = 30
    } else if (this.position === 'right') {
      x = this.app.canvas.width - this.width - 16
      y = 30
    } else {
      x = (this.app.canvas.width - this.width) / 2
      y = 8
    }
    return { x, y }
  }

  private initLayers() {
    this.container.removeChildren()
    this.addBg()
    this.tilesLayer = createContainer({
      width: this.width,
      height: this.height,
      x: 0,
      y: 0,
      parent: this.container,
    })
    this.interactionsLayer = createContainer({
      width: this.width,
      height: this.height,
      x: 0,
      y: 0,
      parent: this.container,
    })
    // this.container.addChild(this.tilesLayer)
    this.container.addChild(this.scoreLayer)
  }

  private calculateScale() {
    const scaleXSteps = Math.floor(this.width / (this.grain * this.scale)) / 2
    const scaleYSteps = Math.floor(this.height / (this.grain * this.scale)) / 2
    this.scaleX = Scale([-scaleXSteps, scaleXSteps], [0, this.width])
    this.scaleY = Scale([-scaleYSteps, scaleYSteps], [0, this.height])
  }
}
