use bevy::prelude::{Bundle, Color, Component, Name, Quat, Transform, Vec2};
use bevy_prototype_lyon::{
    entity::ShapeBundle,
    prelude::{DrawMode, FillMode, GeometryBuilder, Path, PathBuilder, ShapePath, StrokeMode},
    shapes::{self, Line},
};
use bevy_tweening::Lens;

use crate::turtle::Angle;

pub(crate) struct LineAnimationLens {
    start: Vec2,
    end: Vec2,
}

impl LineAnimationLens {
    pub(crate) fn new(start: Vec2, end: Vec2) -> Self {
        Self { start, end }
    }
}

impl Lens<Path> for LineAnimationLens {
    fn lerp(&mut self, target: &mut Path, ratio: f32) {
        let line = shapes::Line(self.start, self.start + ((self.end - self.start) * ratio));
        *target = ShapePath::build_as(&line);
    }
}

#[derive(Bundle)]
pub(crate) struct TurtleDrawLine {
    #[bundle]
    line: ShapeBundle,
    name: Name,
    marker: LineMarker,
}

#[derive(Component, Default)]
struct LineMarker;

impl TurtleDrawLine {
    pub(crate) fn new(start: Vec2, _end: Vec2, index: u64) -> Self {
        Self {
            line: GeometryBuilder::build_as(
                &Line(start, start),
                DrawMode::Outlined {
                    fill_mode: FillMode::color(Color::MIDNIGHT_BLUE),
                    outline_mode: StrokeMode::new(Color::BLACK, 1.0),
                },
                Transform::identity(),
            ),
            name: Name::new(format!("Line {}", index)),
            marker: LineMarker,
        }
    }
}

pub(crate) struct CircleAnimationLens {
    pub start_pos: Vec2,
    pub center: Vec2,
    pub radii: Vec2,
    pub start: Angle,
    pub end: Angle,
}

impl Lens<Path> for CircleAnimationLens {
    fn lerp(&mut self, target: &mut Path, ratio: f32) {
        let mut path_builder = PathBuilder::new();
        path_builder.move_to(self.start_pos);
        // The center point of the radius, then the radii in x and y direction, then the angle that will be drawn, then the x_rotation ?
        path_builder.arc(
            self.center,
            self.radii,
            (self.start.0 + ((self.end.0 - self.start.0) * ratio)).to_radians(),
            0.,
        );
        let line = path_builder.build();
        *target = ShapePath::build_as(&line);
    }
}

pub(crate) struct CircleMovementLens {
    pub center: Vec2,
    pub start: Transform,
    pub end: Angle,
}

impl Lens<Transform> for CircleMovementLens {
    fn lerp(&mut self, target: &mut Transform, ratio: f32) {
        let angle = self.end.0 * ratio;
        let mut rotated = self.start;

        rotated.rotate_around(
            self.center.extend(0.),
            Quat::from_rotation_z(angle.to_radians()),
        );

        *target = rotated;
    }
}

#[derive(Bundle)]

pub(crate) struct TurtleDrawCircle {
    #[bundle]
    line: ShapeBundle,
    name: Name,
    marker: CircleMarker,
}

#[derive(Component, Default)]
struct CircleMarker;

impl TurtleDrawCircle {
    pub(crate) fn new(
        center: Vec2,
        radii: Vec2,
        angle: Angle,
        index: u64,
        start: Vec2,
        end: Vec2,
    ) -> Self {
        let mut path_builder = PathBuilder::new();
        path_builder.move_to(start);
        // The center point of the radius, then the radii in x and y direction, then the angle that will be drawn, then the x_rotation ?
        path_builder.arc(center, radii, angle.0.to_radians(), 0.);

        /* println!("The radiuses: {}", radii);
        path_builder.move_to(Vec2::ZERO);
        path_builder.line_to(center);
        path_builder.line_to(Vec2::new(radii.x, 0.) + center);
        path_builder.move_to(center);
        path_builder.line_to(Vec2::new(0., radii.y) + center);
        path_builder.move_to(center);
        path_builder.line_to(
            center + Vec2::new(radii.x.abs(), 0.).rotate(Vec2::from_angle(angle.0.to_radians())),
        );
        path_builder.move_to(center); */
        let line = path_builder.build();
        println!("Draw Circle: {} {} {:?}", center, radii, angle);

        Self {
            line: GeometryBuilder::build_as(
                &line,
                DrawMode::Outlined {
                    fill_mode: FillMode::color(Color::rgba(0., 0., 0., 0.)),
                    outline_mode: StrokeMode::new(Color::BLACK, 1.0),
                },
                Transform::identity(),
            ),
            name: Name::new(format!("Circle {}", index)),
            marker: CircleMarker,
        }
    }
}