// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
mod player;

pub use player::PlayerController;

use std::time::Instant;

use winit::event::WindowEvent;
use glam::Vec2;

use super::TimeArgs;

use crate::app::config::action::{Action, ActionEvent};
use crate::utils::Clock;

pub(super) struct Controller {
	prev_time: Instant,
	clock: Clock,
	dragging: bool,
	pub pcontrol: PlayerController,
	pub cursor_pos: Vec2,
	prev_cursor_pos: Vec2,
}

impl Controller {
	pub fn new(time: Instant) -> Controller {
		Controller {
			prev_time: time,
			clock: Clock::new_world(),
			dragging: false,
			pcontrol: PlayerController::new(),
			cursor_pos: Vec2::ZERO,
			prev_cursor_pos: Vec2::ZERO,
		}
	}

	pub fn reset(&mut self, time: Instant) {
		self.pcontrol.reset_action_state();
		self.prev_time = time;
		self.dragging = false;
		self.clock = Clock::new_world();
		self.prev_cursor_pos = self.cursor_pos;
	}

	pub fn action(&mut self, action: ActionEvent) {
		self.pcontrol.action(action);

		let prev_dragging = self.dragging;
		match action {
			ActionEvent::Action(Action::Drag, state) => self.dragging = state.pressed(),
			ActionEvent::Action(..) => (),
			ActionEvent::AllReleased => self.dragging = false,
		}

		if self.dragging && !prev_dragging {
			self.prev_cursor_pos = self.cursor_pos;
		}
	}

	pub fn window_event(&mut self, event: &WindowEvent) {
		if let WindowEvent::CursorMoved { position, .. } = event {
			self.cursor_pos = Vec2::new(position.x as f32, position.y as f32);
		}
	}

	pub fn get_time(&mut self) -> TimeArgs {
		let cur_time = Instant::now();
		let dt = cur_time.duration_since(self.prev_time).as_secs_f32();
		self.prev_time = cur_time;
		let steps = self.clock.advance(dt);
		TimeArgs { dt, steps, time_diff: self.clock.get_time_diff() }
	}

	pub fn is_dragging(&self) -> bool {
		self.dragging
	}

	pub fn get_drag(&mut self) -> Option<Vec2> {
		if !self.dragging { return None; }

		let dpos = self.prev_cursor_pos - self.cursor_pos;
		self.prev_cursor_pos = self.cursor_pos;
		Some(dpos)
	}
}
