use bevy::{color::palettes::css::BLACK, prelude::*, window::WindowResized};

use crate::deck::Card;

/// Debugging systems
pub struct DebugPlugin;

impl Plugin for DebugPlugin {
    fn build(&self, app: &mut App) {
        app.add_observer(track_card_info)
            .add_systems(Update, update_window_info)
            .add_systems(Startup, init_ui);
    }
}

#[derive(Component)]
pub(crate) struct DebugText;

#[derive(Component)]
pub(crate) struct WindowInfoText;

fn init_ui(mut commands: Commands) {
    commands
        .spawn((
            Sprite::from_color(Color::BLACK.with_alpha(0.9), [250.0, 150.0].into()),
            DebugText,
            Visibility::Hidden,
            Transform::default().with_translation(Vec3::new(0.0, 0.0, 1.0)),
            PickingBehavior::IGNORE,
        ))
        .with_children(|parent| {
            parent.spawn((
                Text2d("...".to_string()),
                DebugText,
                Transform::default().with_translation(Vec3::new(0.0, 0.0, 2.0)),
                PickingBehavior::IGNORE,
            ));
        });

    commands
        .spawn((
            Node {
                position_type: PositionType::Absolute,
                top: Val::Px(0.0),
                right: Val::Px(0.0),
                ..default()
            },
            BackgroundColor(BLACK.into()),
            GlobalZIndex(1),
        ))
        .with_children(|parent| {
            parent
                .spawn(Button)
                .with_children(|parent| {
                    parent.spawn((
                        Text("-".into()),
                        TextFont {
                            font_size: 60.0,
                            ..default()
                        },
                    ));
                })
                .observe(decrease_scale_ratio);
            parent
                .spawn(Button)
                .with_children(|parent| {
                    parent.spawn((
                        Text("+".into()),
                        TextFont {
                            font_size: 60.0,
                            ..default()
                        },
                    ));
                })
                .observe(increase_scale_ratio);
            parent.spawn((Text("????x????".to_string()), WindowInfoText));
        });
}

fn track_card_info(
    trigger: Trigger<Pointer<Move>>,
    mut transforms: Query<&mut Transform, (With<DebugText>, With<Sprite>)>,
    window: Query<&Window>,
) {
    let p = trigger.pointer_location.position;
    transforms.iter_mut().for_each(|mut t| {
        let offset = window.single().resolution.size() / 2.0;
        let pos = p - offset + Vec2::new(-125.0, 75.0);
        t.translation.x = pos.x;
        t.translation.y = -pos.y;
    });
}

pub(crate) fn set_debug_card(
    trigger: Trigger<Pointer<Over>>,
    cards: Query<&Card>,
    mut vis: Query<&mut Visibility, With<DebugText>>,
    mut debug_text: Query<&mut Text2d, With<DebugText>>,
) {
    let card = cards.get(trigger.entity()).unwrap();
    debug_text.iter_mut().for_each(|mut text| {
        text.0 = format!("{:#?}", card);
    });
    vis.iter_mut().for_each(|mut v| {
        *v = Visibility::Inherited;
    });
}

pub(crate) fn hide_debug_card(
    _trigger: Trigger<Pointer<Out>>,
    mut vis: Query<&mut Visibility, With<DebugText>>,
) {
    vis.iter_mut().for_each(|mut v| {
        *v = Visibility::Hidden;
    });
}

fn update_window_info(
    mut events: EventReader<WindowResized>,
    windows: Query<&mut Window>,
    mut infos: Query<&mut Text, With<WindowInfoText>>,
) {
    events.read().for_each(|_| {
        info!("Window resized");
        let window = windows.single();
        let width = window.resolution.width();
        let height = window.resolution.height();
        let scale_factor = window.resolution.scale_factor();

        let mut info = infos.single_mut();
        info.0 = format!("{:.0}x{:.0} ({:.03})", width, height, scale_factor,);
    });
}

fn increase_scale_ratio(
    _trigger: Trigger<Pointer<Click>>,
    // TODO: Move window scale factor out to non-debug system
    mut windows: Query<&mut Window>,
) {
    info!("increase scale ratio");
    let mut window = windows.single_mut();
    let current = window.scale_factor();
    window.resolution.set_scale_factor(current + 0.05);
}

fn decrease_scale_ratio(
    _trigger: Trigger<Pointer<Click>>,
    // TODO: Move window scale factor out to non-debug system
    mut windows: Query<&mut Window>,
) {
    info!("decrease scale ratio");
    let mut window = windows.single_mut();
    let current = window.scale_factor();
    window.resolution.set_scale_factor(current - 0.05);
}
