import Cog from "@robotical/webapp-types/dist-types/src/application/RAFTs/Cog/Cog";
import { getConnectedCog } from "../../utils/CogManager";
import PlayScene from "../scenes/PlayScene";
import { EventBus } from "../EventBus";

export class Player extends Phaser.Physics.Arcade.Sprite {
  scene: PlayScene;
  jumpSound: Phaser.Sound.HTML5AudioSound | undefined;
  hitSound: Phaser.Sound.HTML5AudioSound | undefined;

  constructor(scene: PlayScene) {
    const x = 0;
    const y = 0;
    super(scene, x, y, "marty-waist");
    this.scene = scene;
    scene.add.existing(this);
    scene.physics.add.existing(this);

    this.init();
    this.scene.events.on(Phaser.Scenes.Events.UPDATE, this.update, this);
  }

  init() {
    if (!this.scene.input.keyboard) return;
   
    this.registerSounds();

    // Handle resizing
    this.scene.scale.once('resize', this.scaleToFit, this);
    this.scene.scale.once('resize', this.positionOnSky, this);

  }

  positionOnSky() {
    const gravity = 2000 * (this.scene.sky?.scaleFactors.height || 1);
    this
      .setOrigin(0.5, 1)  // Origin at the bottom center of the player
      .setGravityY(gravity)
      .setCollideWorldBounds(false)
      .setBodySize(90, 140)
      .setOffset(35, 20)
      .setVisible(false)
      .setDepth(4);

      
    const gameHeight = this.scene.scale.height;

    // Position player at the bottom of the scaled background
    const skyHeight = this.scene.scale.height;
    // const y = gameHeight - (gameHeight - skyHeight); // Slight offset for alignment
    const y = (this.scene.ground?.y || 0) - 140; 
    this.setY(y);
    this.setX(500 * (this.scene.sky?.scaleFactors.width || 1));
    this.setVisible(true);
  }

  scaleToFit() {
    // Use the scale factor from the Sky class to maintain consistency
    const scaleFactor = this.scene.sky?.scaleFactors.height || 1;
    const width = 285;
    const height = 285;

    // Apply the scale factor to the player
    this.setDisplaySize(width * scaleFactor, height * scaleFactor);
    this.setVisible(true);
  }

  getStartTrigger(): boolean {
    /* If the player is connected to a cog, use the cog's buttonClick state to determine if the player should jump / start the game */
    /* Otherwise, use the space key to determine if the player should jump / start the game */
    const connectedCog = getConnectedCog();
    if (connectedCog) {
      return (connectedCog as Cog).publishedDataAnalyser.cogState.buttonClick === "click";
    } else {
      return false; // remove this line and comment in below if you want to use the space key to jump when not connected to a cog
      // if (!this.scene.cursors) return false;
      // const space = this.scene.cursors.space;
      // if (this.scene.input.keyboard && this.scene.input.keyboard.checkDown(this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A), 0)) {
      //   return true;
      // }
      // if (!space) return false;
      // const isSpaceJustDown = Phaser.Input.Keyboard.JustDown(space);
      // // const { space } = this.scene.cursors;
      // // const isSpaceJustDown = Phaser.Input.Keyboard.JustDown(space);
      // return isSpaceJustDown;
    }
  }

  actionDecider(isCogsButtonClickedOrSpaceDown: boolean, onFloor: boolean) {
    if (!isCogsButtonClickedOrSpaceDown) return;
    if (this.scene.currentlySectedBlock?.block === "moveforward") {
      this.moveForward();
    } else if (this.scene.currentlySectedBlock?.block === "movebackward") {
      this.moveBackward();
    } else if (this.scene.currentlySectedBlock?.block === "jump") {
      this.jump(onFloor);
    }
  }

  async moveBackward() {
    const move = 10;
    for (let i = 0; i < move; i++) {
      this.setX(this.x - 1);
      await new Promise((resolve) => setTimeout(resolve, 10));
    }
  }

  async moveForward() {
    const move = 10;
    for (let i = 0; i < move; i++) {
      this.setX(this.x + 1);
      await new Promise((resolve) => setTimeout(resolve, 10));
    }
  }

  jump(onFloor: boolean) {
    if (onFloor) {
      const jumpVelocity = -1200 * (this.scene.sky?.scaleFactors.height || 1);
      this.setVelocityY(jumpVelocity);
      this.jumpSound?.play();
      this.setTexture("marty-jump");
      EventBus.emit('player-jumped', this);
    }

  }

  isOffScreen(): boolean {
    const bounds = this.getBounds();
    const adjustedGameWidth = this.scene.scale.width;
    const isOffScreen = bounds.right < 0 || bounds.left > adjustedGameWidth;
    return isOffScreen;
  }

  update() {
    const isCogsButtonClickedOrSpaceDown = this.getStartTrigger();

    if (this.isOffScreen()) {
      EventBus.emit('player-off-screen', this);
    }
    // if (isCogsButtonClickedOrSpaceDown && !this.scene.isGameRunning && !this.scene.isGameOverVisible) {
    //   this.scene.handleGameStart();
    // }

    // if (!this.scene.isGameRunning) {
    //   return;
    // }

    const onFloor = (this.body as Phaser.Physics.Arcade.Body).onFloor();

    if (onFloor) {
      this.setTexture("marty-waist");
    }
    // get currently selected block and decide movement based on that
    this.actionDecider(isCogsButtonClickedOrSpaceDown, onFloor);

    if (this.body && this.body.deltaAbsY() > 1.39) {
      this.anims.stop();
    } else {
      // this.playRunAnimation();
    }
  }

  registerSounds() {
    this.jumpSound = this.scene.sound.add("jump", { volume: 0.3 }) as Phaser.Sound.HTML5AudioSound;
    this.hitSound = this.scene.sound.add("hit", { volume: 0.4 }) as Phaser.Sound.HTML5AudioSound;
  }

  die() {
    this.anims.pause();
    this.setTexture("marty-hurt");
    this.hitSound?.play();
  }
}
