import { Player } from "../entities/Player";
import { SpriteWithDynamicBody } from "../../types";
import { GameScene } from "./GameScene";
import { EventBus } from "../EventBus";
import { Sky } from "../entities/Sky";
import { Ground } from "../entities/Ground";
import { CogFactory } from "../entities/Cog";
import { StarFactory } from "../entities/Star";
import { ShinyStarFactory } from "../entities/ShinyStar";
import { updateHighScore } from "../../utils/high-score-store";

class PlayScene extends GameScene {

  player: Player | null = null;
  sky: Sky | null = null;
  ground: Phaser.GameObjects.TileSprite | null = null;
  obstacles: Phaser.Physics.Arcade.Group | null = null;
  stars: Phaser.Physics.Arcade.Group | null = null;
  shinyStars: Phaser.Physics.Arcade.Group | null = null;

  cogFactory: CogFactory = new CogFactory(this);
  starFactory: StarFactory = new StarFactory(this);
  shinyStarFactory: ShinyStarFactory = new ShinyStarFactory(this);

  highScoreText: Phaser.GameObjects.Text | undefined;
  scoreText: Phaser.GameObjects.Text | undefined;
  gameOverText: Phaser.GameObjects.Image | undefined;
  restartText: Phaser.GameObjects.Image | undefined;
  gameOverContainer: Phaser.GameObjects.Container | undefined;

  score: number = 0;
  scoreInterval: number = 100;
  scoreDeltaTime: number = 0;

  cogSpawnInterval: number = 3000;
  cogSpawnTime: number = 0;

  starSpawnInterval: number = 5000;
  starSpawnTime: number = 0;

  starShinyStarInterval: number = 30000;
  starShinyStarTime: number = 0;

  gameSpeed: number = 5;
  gameSpeedModifier: number = 1;
  cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
  spaceKey: Phaser.Input.Keyboard.Key | undefined;

  isGameOverVisible: boolean = false;

  progressSound: Phaser.Sound.HTML5AudioSound | undefined;
  progressSoundShiny: Phaser.Sound.HTML5AudioSound | undefined;

  constructor() {
    super("PlayScene");
  }

  async create() {
    this.spaceKey = this.input.keyboard?.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE, true, true);
    this.cursors = this.input.keyboard?.createCursorKeys();

    this.createSky();
    this.createGround();
    this.createPlayer();
    this.handleGroundPlayerCollision();

    this.createObstacles();
    this.handleObstacleCollisions();

    this.createStars();
    this.handleStarCollisions();

    this.createShinyStars();
    this.handleShinyStarCollisions();

    this.createGameoverContainer();
    this.createScore();

    this.handleGameRestartSetup();

    this.progressSound = this.sound.add("progress", { volume: 0.2 }) as Phaser.Sound.HTML5AudioSound;
    this.progressSoundShiny = this.sound.add("progress", { volume: 0.5 }) as Phaser.Sound.HTML5AudioSound;
    EventBus.emit('current-scene-ready', this);
  }
  handleGroundPlayerCollision() {
    if (!this.ground) return;
    if (!this.player) return;
    this.physics.add.collider(this.ground, this.player, () => {
    });
  }

  update(time: number, delta: number): void {
    if (!this.isGameRunning) return;
    EventBus.emit('play-scene-updated', this);

    this.cogSpawnTime += delta;
    this.starSpawnTime += delta;
    this.starShinyStarTime += delta;

    this.scoreDeltaTime += delta;

    if (this.scoreDeltaTime >= this.scoreInterval) {
      this.score++;
      this.scoreDeltaTime = 0;

      if (this.score % 100 === 0) {
        this.gameSpeedModifier += 0.2;
        this.tweens.add({
          targets: this.scoreText,
          duration: 100,
          repeat: 3,
          alpha: 0,
          yoyo: true
        });
      }
    }

    if (this.cogSpawnTime >= this.cogSpawnInterval) {
      this.spawnObstacle();
      this.cogSpawnTime = 0;
    }

    if (this.starSpawnTime >= this.starSpawnInterval) {
      this.spawnStar();
      this.starSpawnTime = 0;
    }

    if (this.starShinyStarTime >= this.starShinyStarInterval) {
      this.spawnShinyStar();
      this.starShinyStarTime = 0;
    }

    Phaser.Actions.IncX(this.obstacles?.getChildren() || [], -this.gameSpeed * this.gameSpeedModifier);
    Phaser.Actions.IncX(this.stars?.getChildren() || [], -this.gameSpeed * this.gameSpeedModifier);
    Phaser.Actions.IncX(this.shinyStars?.getChildren() || [], -this.gameSpeed * this.gameSpeedModifier);

    const score = Array.from(String(this.score), Number);

    for (let i = 0; i < 5 - String(this.score).length; i++) {
      score.unshift(0);
    }

    this.scoreText?.setText(score.join(""));

    this.obstacles?.getChildren().forEach((obstacle: Phaser.GameObjects.GameObject) => {
      if ((obstacle as SpriteWithDynamicBody).getBounds().right < 0) {
        this.obstacles?.remove(obstacle);
      }
    });

    this.stars?.getChildren().forEach((star: Phaser.GameObjects.GameObject) => {
      if ((star as SpriteWithDynamicBody).getBounds().right < 0) {
        this.stars?.remove(star);
      }
    });

    this.shinyStars?.getChildren().forEach((shinyStar: Phaser.GameObjects.GameObject) => {
      if ((shinyStar as SpriteWithDynamicBody).getBounds().right < 0) {
        this.shinyStars?.remove(shinyStar);
      }
    });
  }

  createPlayer() {
    this.player = new Player(this);
  }

  createSky() {
    this.sky = new Sky(this);
  }

  createGround() {
    this.ground = new Ground(this);
  }

  createObstacles() {
    this.obstacles = this.physics.add.group();
  }

  createStars() {
    this.stars = this.physics.add.group();
  }

  createShinyStars() {
    this.shinyStars = this.physics.add.group();
  }

  createGameoverContainer() {
    this.gameOverText = this.add.image(0, 0, "game-over");
    this.restartText = this.add.image(0, 80, "restart").setInteractive();

    this.gameOverContainer = this.add
      .container(this.scale.width / 2, (this.scale.height) / 4)
      .add([this.gameOverText, this.restartText])
      .setAlpha(0)
      .setDepth(3);
  }

  createScore() {
    this.scoreText = this.add.text(this.scale.width, 0, "00000", {
      fontSize: 30,
      fontFamily: "Arial",
      color: "#535353",
      resolution: 5
    }).setOrigin(1, 0).setAlpha(1);

    this.highScoreText = this.add.text(this.scoreText.getBounds().left - 20, 0, "00000", {
      fontSize: 30,
      fontFamily: "Arial",
      color: "#535353",
      resolution: 5
    }).setOrigin(1, 0).setAlpha(1);
  }

  spawnObstacle() {
    if (!this.obstacles) return;
    this.cogFactory.create(this.obstacles);
  }

  spawnStar() {
    if (!this.stars) return;
    this.starFactory.create(this.stars);
  }

  spawnShinyStar() {
    if (!this.shinyStars) return;
    this.shinyStarFactory.create(this.shinyStars);
  }

  handleGameStart() {
    const rollOutEvent = this.time.addEvent({
      delay: 1000 / 60,
      loop: true,
      callback: () => {
        this.player?.setVelocityX(80);

        rollOutEvent.remove();
        if (this.ground) this.ground.width = this.gameWidth;
        this.player?.setVelocityX(0);
        // this.scoreText.setAlpha(1);
        this.isGameRunning = true;
      }
    });
  }

  handleGameRestartSetup() {
    this.restartText?.on("pointerdown", () => {
      this.handleGameRestart();
    });
  }

  handleGameRestart() {
    this.physics.resume();
    this.player?.setVelocityY(0);

    this.obstacles?.clear(true, true);
    this.stars?.clear(true, true);
    this.shinyStars?.clear(true, true);

    this.gameOverContainer?.setAlpha(0);
    this.isGameOverVisible = false;
    this.anims.resumeAll();

    this.isGameRunning = true;

    this.player?.setTexture("marty-waist");
  }

  handleObstacleCollisions() {
    if (!this.obstacles) return;
    if (!this.player) return;
    this.physics.add.collider(this.obstacles, this.player, () => {
      this.isGameRunning = false;
      this.physics.pause();
      this.anims.pauseAll();

      this.player?.die();

      this.gameOverContainer?.setAlpha(1);
      this.isGameOverVisible = true;

      const newHighScore = this.highScoreText?.text.substring(this.highScoreText.text.length - 5);
      const newScore = Number(this.scoreText?.text) > Number(newHighScore) ? this.scoreText?.text : newHighScore;

      updateHighScore(Number(newScore));

      this.highScoreText?.setText("HI " + newScore);
      this.highScoreText?.setAlpha(1);

      this.cogSpawnTime = 0;
      this.score = 0;
      this.scoreDeltaTime = 0
      this.gameSpeedModifier = 1;

      EventBus.emit('die', this);
    });
  }

  handleStarCollisions() {
    if (!this.stars) return;
    if (!this.player) return;
    this.physics.add.overlap(this.stars, this.player, (player, star) => {
      this.stars?.remove((star as Phaser.GameObjects.GameObject));
      star.destroy();
      this.score += 40;
      this.progressSound?.play();
      EventBus.emit('star-collected', this);
    });
  }

  handleShinyStarCollisions() {
    if (!this.shinyStars) return;
    if (!this.player) return;
    this.physics.add.overlap(this.shinyStars, this.player, (player, star) => {
      this.shinyStars?.remove((star as Phaser.GameObjects.GameObject));
      star.destroy();
      this.score += 50;
      this.progressSoundShiny?.play();
    });
  }


}

export default PlayScene;
