import { Player } from "../entities/Player";
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";
import { safeAddSound } from "../../utils/safe-add-sound";

class PlayScene extends GameScene {

  player: Player | null = null;
  sky: Sky | null = null;
  ground: Ground | 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;
  collectedStars: 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.BaseSound | undefined;
  progressSoundShiny: Phaser.Sound.BaseSound | undefined;

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

  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 = safeAddSound(this, "progress", { volume: 0.2 });
    this.progressSoundShiny = safeAddSound(this, "progress", { volume: 0.5 });
    EventBus.emit('current-scene-ready', this);
    this.syncScaleBounds();
    this.scale.on('resize', this.syncScaleBounds, this);
    this.events.once(Phaser.Scenes.Events.SHUTDOWN, () => {
      this.scale.off('resize', this.syncScaleBounds, this);
    });
  }

  syncScaleBounds() {
    if (!this.physics.world) return;
    this.physics.world.setBounds(0, 0, this.scale.width, this.scale.height);
    this.sky?.scaleToFit();
    this.ground?.scaleToFit();
    this.ground?.positionOnSky();
    this.player?.scaleToFit();
    this.player?.positionOnSky();
  }
  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.player && this.ground) {
      const isPlayerTouchingGround = this.physics.overlap(this.player, this.ground);
      this.player.canMoveDown = !isPlayerTouchingGround;
      this.player.canMoveUp = this.player.getBounds().top > 8;
    }

    if (this.isPreviewOnly) return;
    if (!this.isGameRunning) return;

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

    this.scoreDeltaTime += delta;

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

    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;
    }

    const frameScale = delta / (1000 / 60);
    const deltaX = -this.gameSpeed * this.gameSpeedModifier * frameScale;
    this.moveAndDestroyOffscreenChildren(this.obstacles, deltaX);
    this.moveAndDestroyOffscreenChildren(this.stars, deltaX);
    this.moveAndDestroyOffscreenChildren(this.shinyStars, deltaX);
  }

  updateScoreText() {
    this.scoreText?.setText(String(this.score).padStart(5, "0").slice(-5));
  }

  moveAndDestroyOffscreenChildren(group: Phaser.Physics.Arcade.Group | null, deltaX: number) {
    const children = group?.getChildren();
    if (!children?.length) return;

    for (let index = children.length - 1; index >= 0; index--) {
      const child = children[index] as Phaser.Physics.Arcade.Sprite;
      child.x += deltaX;

      if (child.x + child.displayWidth < -8) {
        group?.remove(child, true, true);
      }
    }
  }

  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(0);

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

  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.scale.width;
        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-in-plane");
    this.player?.positionOnSky();
  }

  handleObstacleCollisions() {
    if (!this.obstacles) return;
    if (!this.player) return;
    this.physics.add.collider(this.obstacles, this.player, () => {
      if (this.isPreviewOnly) return;
      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();
      this.collectedStars++;
      EventBus.emit('star-collected', this);
      EventBus.emit('tutorial-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;
