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

use bevy::prelude::*;

use crate::{
	common::{animation::SpriteAnimation, velocity::Velocity},
	level::Unit,
	GameState, START_POSITION,
};

pub struct PlayerPlugin;

impl Plugin for PlayerPlugin {
	fn build(&self, app: &mut App) {
		app.add_systems(Startup, setup);
		app.add_systems(
			FixedUpdate,
			(move_player).run_if(in_state(GameState::Playing)),
		);
	}
}

#[derive(Component)]
#[require(Unit, SpriteAnimation)]
pub struct Player;

fn setup(
	mut commands: Commands,
	asset_server: Res<AssetServer>,
	mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
) {
	let layout = TextureAtlasLayout::from_grid(UVec2::splat(135), 2, 1, None, None);
	let layout_handle = texture_atlas_layouts.add(layout);

	commands.spawn((
		Player,
		Transform {
			translation: START_POSITION,
			scale: Vec2::new(0.5, 0.5).extend(1.0),
			..Default::default()
		},
		Visibility::Hidden,
		Sprite {
			image: asset_server.load("player.png"),
			texture_atlas: Some(TextureAtlas {
				layout: layout_handle,
				index: 0,
			}),
			..Default::default()
		},
		SpriteAnimation::new(1, Timer::from_seconds(0.3, TimerMode::Repeating)),
	));
}

fn move_player(
	keys: Res<ButtonInput<KeyCode>>,
	gamepads: Query<&Gamepad>,
	mut query: Query<(&mut Transform, &mut Velocity), With<Player>>,
	window: Query<&Window>,
) {
	let (mut transform, mut velocity) = query.single_mut();
	let gamepad = gamepads.get_single();
	velocity.0 = Vec2::ZERO;

	if let Ok(gamepad) = gamepad {
		handle_gamepad_movement(gamepad, &mut velocity);
	}

	if keys.pressed(KeyCode::ArrowRight) {
		velocity.x += 1.0;
	}
	if keys.pressed(KeyCode::ArrowLeft) {
		velocity.x -= 1.0;
	}
	if keys.pressed(KeyCode::ArrowUp) {
		velocity.y += 1.0;
	}
	if keys.pressed(KeyCode::ArrowDown) {
		velocity.y -= 1.0;
	}

	if velocity.length() > 0.0 {
		velocity.0 = velocity.normalize() * 400.0;
		let angle = velocity.to_angle() - PI / 2.0;
		let angle = Quat::from_rotation_z(angle);
		transform.rotation = angle;
	}

	let window = window.single();
	let screen_size: Vec3 = window.physical_size().as_vec2().extend(1.0);
	transform.translation = transform.translation.clamp(Vec3::ZERO, screen_size);
}

fn handle_gamepad_movement(gamepad: &Gamepad, velocity: &mut Velocity) {
	let axis_lx = gamepad.get(GamepadAxis::LeftStickX).unwrap_or_default();
	let axis_ly = gamepad.get(GamepadAxis::LeftStickY).unwrap_or_default();

	let left_stick = Vec2::new(axis_lx, axis_ly);
	if left_stick.length() > 0.25 {
		*velocity = Velocity(left_stick);
		return;
	}

	if gamepad.pressed(GamepadButton::DPadRight) {
		velocity.x += 1.0;
	}
	if gamepad.pressed(GamepadButton::DPadLeft) {
		velocity.x -= 1.0;
	}
	if gamepad.pressed(GamepadButton::DPadUp) {
		velocity.y += 1.0;
	}
	if gamepad.pressed(GamepadButton::DPadDown) {
		velocity.y -= 1.0;
	}
}
