use std::rc::Rc;

use druid::{
	kurbo::{Line, Size},
	piet::{LineCap, LineJoin, RenderContext, StrokeStyle},
	widget::prelude::*,
	Point,
};
use tf_player::player;

use crate::{command, theme};

#[derive(Default)]
pub struct PlayerBar {
	position_preview: f64,
}

type Data = Rc<player::state::Playing>;

impl Widget<Data> for PlayerBar {
	fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut Data, _env: &Env) {
		match event {
			Event::MouseDown(_) => {
				if !ctx.is_disabled() {
					ctx.set_active(true);
					ctx.request_paint();
				}
			}
			Event::MouseMove(evt) => {
				if ctx.is_active() {
					self.position_preview = evt.pos.x / ctx.size().width;
					ctx.request_paint();
				}
			}
			Event::MouseUp(evt) => {
				if ctx.is_active() && !ctx.is_disabled() {
					let position = data.song.duration.mul_f64(evt.pos.x / ctx.size().width);
					ctx.submit_command(command::PLAYER_SEEK.with(position));
					ctx.request_paint();
				}
				ctx.set_active(false);
			}
			_ => (),
		}
	}

	fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, _data: &Data, _env: &Env) {
		if let LifeCycle::HotChanged(_) | LifeCycle::DisabledChanged(_) = event {
			ctx.request_paint();
		}
	}

	fn update(&mut self, ctx: &mut UpdateCtx, _old_data: &Data, _data: &Data, _env: &Env) {
		ctx.request_paint();
	}

	fn layout(
		&mut self,
		_ctx: &mut LayoutCtx,
		bc: &BoxConstraints,
		_data: &Data,
		_env: &Env,
	) -> Size {
		Size::new(bc.max().width, 24.0)
	}

	fn paint(&mut self, ctx: &mut PaintCtx, data: &Data, env: &Env) {
		let size = ctx.size();

		let left = Point::new(0.0, size.height / 2.0);

		let right = Point::new(size.width, size.height / 2.0);

		ctx.stroke_styled(
			Line::new(left, right),
			&env.get(theme::BACKGROUND_HIGHLIGHT0),
			6.0,
			&StrokeStyle {
				line_join: LineJoin::Round,
				line_cap: LineCap::Round,
				..Default::default()
			},
		);

		let progress = if ctx.is_active() {
			self.position_preview
		} else {
			data.offset.as_secs_f64() / data.song.duration.as_secs_f64()
		};
		let progress_right = Point::new(size.width * progress, size.height / 2.0);

		ctx.stroke_styled(
			Line::new(left, progress_right),
			&env.get(theme::ACCENT),
			6.0,
			&StrokeStyle {
				line_join: LineJoin::Round,
				line_cap: LineCap::Round,
				..Default::default()
			},
		);
	}
}