use std::f32::consts::PI;

use crate::{deck::*, *};
use bevy::{
    animation::{animated_field, AnimationTarget, AnimationTargetId},
    prelude::*,
};
use view::ViewState;

pub struct SetupPlugin;

impl Plugin for SetupPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(
            OnEnter(GameState::Setup),
            (setup_background, setup_cards, setup_camera, start_play).chain(),
        );
    }
}

#[derive(Component)]
pub(crate) struct CardAnimations {
    pub rotate: AnimationNodeIndex,
}

/// Setup drawing our cards on the screen
pub(crate) fn setup_cards(
    mut commands: Commands,
    deck: Res<Deck>,
    mut clips: ResMut<Assets<AnimationClip>>,
    mut graphs: ResMut<Assets<AnimationGraph>>,
) {
    let animation_player = AnimationPlayer::default();
    commands
        .spawn((
            Transform::default(),
            Visibility::default(),
            ViewState::Play,
            animation_player,
        ))
        .with_children(|parent| {
            Deck::iter_shuffled()
                .enumerate()
                .for_each(|(i, this_card)| {
                    let this = deck
                        .cards
                        .get(&this_card)
                        .unwrap_or_else(|| panic!("fech card sprite {:?}", this_card))
                        .clone();
                    let this_sprite = Sprite {
                        custom_size: Some(Vec2::new(80.0, 128.0)),
                        ..this
                    };
                    let order = play::DeckOrder(i as u8);

                    let name = Name::new(format!("{}", this_card));
                    let animation_components = {
                        let mut animation = AnimationClip::default();
                        let target = AnimationTargetId::from_name(&name);
                        let curve = AnimatableCurve::new(
                            animated_field!(Transform::rotation),
                            AnimatableKeyframeCurve::new(
                                [0.0, 1.0, 2.0, 3.0, 4.0].into_iter().zip([
                                    Quat::IDENTITY,
                                    Quat::from_axis_angle(Vec3::Y, PI / 2.),
                                    Quat::from_axis_angle(Vec3::Y, PI / 2. * 2.),
                                    Quat::from_axis_angle(Vec3::Y, PI / 2. * 3.),
                                    Quat::IDENTITY,
                                ]),
                            )
                            .expect("Rotation animation"),
                        );
                        animation.add_curve_to_target(target, curve);
                        let animation_handle = clips.add(animation);
                        let (graph, rotate) = AnimationGraph::from_clip(animation_handle);
                        let animation_graph_handle = AnimationGraphHandle(graphs.add(graph));
                        let indexes = CardAnimations { rotate };
                        let target = AnimationTarget {
                            id: target,
                            player: parent.parent_entity(),
                        };
                        (animation_graph_handle, indexes, target)
                    };
                    // Card Animations:
                    //   active_card_animation = AnimationClip::default() // simple rotation
                    //   for each (X, Y) in board:
                    //     deck_to_X_Y = AnimationClip::default() // Move from deck to X Y position
                    //     X_Y_to_sets = AnimationClip::default() // Move from X Y position to sets pile
                    //   All need AnimationTarget, AnimationGraphHandle, and AnimationPlayer
                    parent
                        .spawn((
                            this_sprite,
                            this_card,
                            order,
                            Visibility::Hidden,
                            name,
                            animation_components,
                        ))
                        .observe(play::place_card)
                        .observe(debug::set_debug_card)
                        .observe(debug::hide_debug_card)
                        .observe(play::reset_rotation)
                        .observe(play::toggle_selected);
                });
        });
}

/// Setup our camera to view cardson the screen
pub(crate) fn setup_camera(mut commands: Commands) {
    commands.spawn((
        Camera2d,
        Camera {
            hdr: true,
            ..default()
        },
    ));
}

pub(crate) fn setup_background(
    mut commands: Commands,
    server: Res<AssetServer>,
    window: Query<&Window>,
) {
    commands.spawn((
        Transform::default().with_translation(Vec3::new(0.0, 0.0, -1.0)),
        Sprite {
            image: server.load("background.png"),
            custom_size: Some(window.single().resolution.size() * 1.1),
            ..default()
        },
    ));
}

/// Finish the setup state by progressing to the play state
pub(crate) fn start_play(
    mut game_state: ResMut<NextState<GameState>>,
    mut view_state: ResMut<NextState<ViewState>>,
) {
    info!("starting play");
    game_state.set(GameState::Main);
    view_state.set(ViewState::Menu);
}

fn setup_animations(mut commands: Commands) {
    // TODO: (example: https://bevyengine.org/examples/animation/animated-transform/)
    // Button Animations:
    //   active_button_animation = AnimationClip::default() // color and size
}
