use std::f32::consts::PI;

use godot::classes::{AnimatedSprite2D, Area2D, CollisionShape2D, IArea2D, Input};
use godot::global::atan2;
use godot::prelude::*;

#[derive(GodotClass)]
#[class(base=Area2D)]
pub struct Player {
  #[export]
  speed: f32,
  #[export]
  velocity: Vector2,
  screen_size: Rect2,

  // required
  base: Base<Area2D>,
}

#[godot_api]
impl IArea2D for Player {
  fn init(base: Base<Area2D>) -> Self {
    Self {
      speed: 400.0,
      velocity: Vector2::ZERO,
      screen_size: Rect2::default(),

      base,
    }
  }

  fn ready(&mut self) {
    self.screen_size = self.base().get_viewport_rect();
    self.base_mut().hide();

    self.signals().body_entered().connect_self(Self::body_entered);
  }

  fn process(&mut self, delta: f32) {
    let input = Input::singleton();
    let mut animated_sprite_2d = self.base().get_node_as::<AnimatedSprite2D>("AnimatedSprite2D");

    if input.is_action_pressed("move_right") {
      self.velocity.x += 1.0 * self.speed;
    }
    if input.is_action_pressed("move_left") {
      self.velocity.x -= 1.0 * self.speed;
    }
    if input.is_action_pressed("move_down") {
      self.velocity.y += 1.0 * self.speed;
    }
    if input.is_action_pressed("move_up") {
      self.velocity.y -= 1.0 * self.speed;
    }

    if self.velocity.length() > 0.0 {
      animated_sprite_2d.set_animation("up");
      animated_sprite_2d.set_rotation(atan2(self.velocity.y as f64, self.velocity.x as f64) as f32 + (PI / 2.0));
      animated_sprite_2d.play();
    } else {
      animated_sprite_2d.stop();
      animated_sprite_2d.set_frame(0);
    }

    let mut position = self.base().get_position();
    position = (position + (self.velocity * delta)).clamp(Vector2::ZERO, self.screen_size.size);
    self.velocity *= 0.9;

    self.base_mut().set_position(position);
  }
}

#[godot_api]
impl Player {
  #[signal]
  pub fn hit();

  fn body_entered(&mut self, _body: Gd<Node2D>) {
    let mut collision_shape_2d = self.base().get_node_as::<CollisionShape2D>("CollisionShape2D");

    self.base_mut().hide();
    self.signals().hit().emit();
    collision_shape_2d.set_deferred("disabled", &Variant::from(true));
  }

  #[func]
  pub fn start(&mut self, position: Vector2) {
    let mut collision_shape_2d = self.base().get_node_as::<CollisionShape2D>("CollisionShape2D");

    self.base_mut().set_position(position);
    self.base_mut().show();
    collision_shape_2d.set_disabled(false);
  }
}
