use std::time::{Duration, Instant};

use color_eyre::{eyre::eyre, owo_colors::OwoColorize, Result};
use gilrs::{Gamepad, Gilrs};
use ratatui::{
	buffer::Buffer,
	crossterm::event::{self, Event, KeyCode, KeyEventKind},
	layout::{Alignment, Constraint, Flex, Layout, Rect},
	style::{palette::tailwind, Color, Style, Stylize},
	symbols::Marker,
	widgets::{
		canvas::{Canvas, Circle, Shape},
		Block, BorderType, Gauge, Padding, Paragraph, Widget,
	},
	DefaultTerminal,
};
use Constraint::{Fill, Length, Min, Percentage};

use crate::gamepad_manager::GamepadManager;

pub struct App {
	pub manager: GamepadManager,

	state: AppState,
	tick: u64,
}

#[derive(Default, PartialEq, Eq)]
pub enum AppState {
	#[default]
	Running,
	Quitting,
}

impl App {
	pub fn new(manager: GamepadManager) -> Self {
		App {
			manager,
			state: AppState::Running,

			tick: 0,
		}
	}

	pub fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
		let tick_rate = Duration::from_millis(20);
		let mut last_tick = Instant::now();

		while self.state == AppState::Running {
			terminal.draw(|frame| frame.render_widget(&self, frame.area()))?;

			let timeout = tick_rate.saturating_sub(last_tick.elapsed());
			if event::poll(timeout)? {
				self.handle_events()?;
			}
			self.handle_gamepad_inputs()?;

			if last_tick.elapsed() >= tick_rate {
				self.update();
				last_tick = Instant::now();
			}
		}
		Ok(())
	}

	fn handle_gamepad_inputs(&mut self) -> Result<()> {
		while let Some(gilrs::Event { id, .. }) = self.manager.gilrs.next_event() {
			self.manager.set_active_gamepad(id);
		}
		Ok(())
	}

	fn handle_events(&mut self) -> Result<()> {
		if let ratatui::crossterm::event::Event::Key(key) = event::read()? {
			if key.kind == KeyEventKind::Press {
				match key.code {
					KeyCode::Char('r') => {
						self.manager.scan_gamepads();
						return Ok(());
					}
					KeyCode::Char('v') => self.manager.test_weak_ff(),
					KeyCode::Char('V') => self.manager.test_strong_ff(),
					KeyCode::Char('q') | KeyCode::Char('Q') | KeyCode::Esc => self.quit(),
					_ => {}
				}
			}
		}
		Ok(())
	}

	fn update(&mut self) {
		self.tick = self.tick.wrapping_add(1);
	}

	fn quit(&mut self) {
		self.state = AppState::Quitting;
	}

	// fn render_title(area: Rect, buf: &mut Buffer) {
	// 	Paragraph::new("App Example Title")
	// 		.block(
	// 			Block::bordered()
	// 				.border_type(BorderType::Rounded)
	// 				.padding(Padding::top(1)),
	// 		)
	// 		.alignment(Alignment::Center)
	// 		.render(area, buf);
	// }
	//
	// fn render_connected_gamepad(&self, area: Rect, buf: &mut Buffer) {
	// 	Paragraph::new(format!(
	// 		"{} connected gamepads",
	// 		self.manager.connected_gamepads()
	// 	))
	// 	.block(
	// 		Block::bordered()
	// 			.border_type(BorderType::Rounded)
	// 			.padding(Padding::top(1)),
	// 	)
	// 	.alignment(Alignment::Center)
	// 	.bold()
	// 	.render(area, buf);
	// }

	fn render_action_buttons(&self, area: Rect, buf: &mut Buffer) {
		Block::bordered().render(area, buf);

		let north_button = self.create_action_button_ui(gilrs::Button::North);
		let east_button = self.create_action_button_ui(gilrs::Button::East);
		let south_button = self.create_action_button_ui(gilrs::Button::South);
		let west_button = self.create_action_button_ui(gilrs::Button::West);

		let layers = Layout::vertical([Fill(1), Fill(1), Fill(1)]);
		let [top, mid, bot] = layers.areas(area);

		let top_layer = Layout::horizontal([Fill(1), Fill(1), Fill(1)]);
		let [_, north, _] = top_layer.areas(top);

		let mid_layer = Layout::horizontal([Fill(1), Fill(1), Fill(1)]);
		let [west, _, east] = mid_layer.areas(mid);

		let bot_layer = Layout::horizontal([Fill(1), Fill(1), Fill(1)]);
		let [_, south, _] = bot_layer.areas(bot);

		north_button.render(north, buf);
		east_button.render(east, buf);
		south_button.render(south, buf);
		west_button.render(west, buf);
	}

	fn render_dpad_buttons(&self, area: Rect, buf: &mut Buffer) {
		Block::bordered().render(area, buf);

		let up_button = self.create_action_button_ui(gilrs::Button::DPadUp);
		let right_button = self.create_action_button_ui(gilrs::Button::DPadRight);
		let down_button = self.create_action_button_ui(gilrs::Button::DPadDown);
		let left_button = self.create_action_button_ui(gilrs::Button::DPadLeft);

		let layers = Layout::vertical([Fill(1), Fill(1), Fill(1)]);
		let [top, mid, bot] = layers.areas(area);

		let top_layer = Layout::horizontal([Fill(1), Fill(1), Fill(1)]);
		let [_, up, _] = top_layer.areas(top);

		let mid_layer = Layout::horizontal([Fill(1), Fill(1), Fill(1)]);
		let [left, _, right] = mid_layer.areas(mid);

		let bot_layer = Layout::horizontal([Fill(1), Fill(1), Fill(1)]);
		let [_, down, _] = bot_layer.areas(bot);

		up_button.render(up, buf);
		right_button.render(right, buf);
		down_button.render(down, buf);
		left_button.render(left, buf);
	}

	fn render_setting_buttons(&self, area: Rect, buf: &mut Buffer) {
		Block::bordered().render(area, buf);

		let select_button = self.create_action_button_ui(gilrs::Button::Select);
		let start_button = self.create_action_button_ui(gilrs::Button::Start);

		let layers = Layout::horizontal([Fill(1), Fill(1), Fill(1), Fill(1), Fill(1)]);
		let [_, select_area, _, start_area, _] = layers.areas(area);

		let select_layer = Layout::vertical([Fill(1), Fill(1), Fill(1), Fill(1)]);
		let [_, select, _, _] = select_layer.areas(select_area);

		let start_layer = Layout::vertical([Fill(1), Fill(1), Fill(1), Fill(1)]);
		let [_, start, _, _] = start_layer.areas(start_area);

		select_button.render(select, buf);
		start_button.render(start, buf);
	}

	fn render_trigger_buttons(&self, area: Rect, buf: &mut Buffer) {
		Block::bordered().render(area, buf);

		let r1_button = self.create_action_button_ui(gilrs::Button::RightTrigger);
		let r2_button = self.create_action_button_ui(gilrs::Button::RightTrigger2);
		let l1_button = self.create_action_button_ui(gilrs::Button::LeftTrigger);
		let l2_button = self.create_action_button_ui(gilrs::Button::LeftTrigger2);

		let layers = Layout::horizontal([
			Fill(2),
			Fill(1),
			Fill(1),
			Fill(1),
			Fill(4),
			Fill(1),
			Fill(1),
			Fill(1),
			Fill(2),
		]);
		let [_, l2_area, _, l1_area, _, r1_area, _, r2_area, _] = layers.areas(area);

		let r1_layer = Layout::vertical([Fill(2), Fill(1), Fill(2)]);
		let [_, r1, _] = r1_layer.areas(r1_area);

		let r2_layer = Layout::vertical([Fill(1), Fill(3), Fill(1)]);
		let [_, r2, _] = r2_layer.areas(r2_area);

		let l1_layer = Layout::vertical([Fill(2), Fill(1), Fill(2)]);
		let [_, l1, _] = l1_layer.areas(l1_area);

		let l2_layer = Layout::vertical([Fill(1), Fill(3), Fill(1)]);
		let [_, l2, _] = l2_layer.areas(l2_area);

		r1_button.render(r1, buf);
		r2_button.render(r2, buf);
		l1_button.render(l1, buf);
		l2_button.render(l2, buf);

		//TODO: For PS4+ controllers doesn't have dedicated trigger push force
		// let gauge_percentage = match self.manager.active_gamepad() {
		// 	Ok(gamepad) => match gamepad.axis_data(gilrs::Axis::Unknown) {
		// 		Some(ad) => ad.value(),
		// 		None => 0.0,
		// 	},
		// 	Err(_) => 0.0,
		// };
		// let gauge_percentage = 0;

		// Gauge::default()
		// 	.gauge_style(Color::Green)
		// 	.bg(Color::DarkGray)
		// 	.ratio(gauge_percentage.into())
		// 	.render(r2, buf);
	}

	fn create_action_button_ui(&self, dir: gilrs::Button) -> Block {
		let color = match self.manager.active_gamepad() {
			Ok(gamepad) => match gamepad.is_pressed(dir) {
				true => Color::Green,
				false => Color::DarkGray,
			},
			Err(_) => Color::DarkGray,
		};

		Block::new().style(Style::default().bg(color))
	}
}

impl Widget for &App {
	fn render(self, area: Rect, buf: &mut Buffer) {
		let layout = Layout::vertical([Percentage(100)]);
		let [inner_area] = layout.areas(area);

		let gamepad_layout = Layout::vertical([Fill(2), Fill(4), Fill(3)]);
		let [triggers, buttons, joysticks] = gamepad_layout.areas(inner_area);

		let buttons_layout = Layout::horizontal([Fill(2), Fill(2), Fill(2)]);
		let [left_buttons, mid_buttons, right_buttons] = buttons_layout.areas(buttons);

		// let details_layout = Layout::horizontal([Fill(2), Fill(2)]);
		// let [right_details_area, left_details_area] = details_layout.areas(details_area);

		let mut title_label = Block::bordered();
		title_label = match self.manager.active_gamepad() {
			Ok(gp) => title_label
				.title(gp.name().to_string())
				.title_style(Color::Rgb(255, 165, 35)),
			Err(_) => title_label.title("No active device".to_string()),
		};
		title_label.render(inner_area, buf);

		// Block::bordered()
		// 	.style(Style::default().bg(tailwind::GREEN.c900))
		// 	.render(right_details_area, buf);

		// Block::new()
		// 	.style(Style::default().bg(tailwind::YELLOW.c300))
		// 	.render(details_area, buf);

		self.render_dpad_buttons(left_buttons, buf);
		self.render_setting_buttons(mid_buttons, buf);
		self.render_action_buttons(right_buttons, buf);
		self.render_trigger_buttons(triggers, buf);

		// Block::bordered()
		// 	.style(Style::default().bg(tailwind::TEAL.c300))
		// 	.render(left_details_area, buf);

		// let gauge_progress: u16 = self
		// 	.tick
		// 	.wrapping_div(100)
		// 	.clamp(0, 100)
		// 	.try_into()
		// 	.unwrap();
		// Gauge::default()
		// 	.gauge_style(tailwind::BLUE.c900)
		// 	.percent(gauge_progress)
		// 	.render(right_details_area, buf);

		// self.render_title(title_area, buf);
		// self.render_tabs(tabs_area, buf);
		// self.selected_tab.render(inner_area, buf);
		// render_footer(footer_area, buf);
	}
}