#![warn(clippy::all,clippy::pedantic)]
use crate::prelude::*;

//player input systems component. it takes inputs from the resource
//map, key, and camera, which is passed into the system executing in the main
#[system]
#[write_component(Point)]
#[read_component(Player)]
#[read_component(Enemy)]
#[write_component(Health)]
#[read_component(Item)]
#[read_component(Carried)]
#[read_component(Weapon)]
pub fn player_input(
    ecs: &mut SubWorld,
 //   #[resource] map: &Map,
    commands:&mut CommandBuffer,
    #[resource] key: &Option<VirtualKeyCode>,
 //   #[resource] camera: &mut Camera,
    #[resource] turn_state: &mut TurnState
){
    if let Some(key) = key {
        

        //find the players
        //let mut players = <(Entity, &mut Point)>::query()
        //    .filter(component::<Player>());
        /*players.iter_mut(ecs).for_each(|(entity, pos)|{
            let destination = *pos + delta;
            commands
                .push(((),WantsToMove{entity:*entity,destination}));
        });*/
        let mut players = <(Entity, &Point)>::query().filter(component::<Player>());

        let delta = match key {
            VirtualKeyCode::Left => Point::new(-1,0),
            VirtualKeyCode::Right => Point::new(1,0),
            VirtualKeyCode::Up => Point::new(0,-1),
            VirtualKeyCode::Down => Point::new(0,1),
            VirtualKeyCode::G => {
                let (player, player_pos) = players
                    .iter(ecs)
                    .find_map(|(entity, pos)| Some((*entity, *pos)))
                    .unwrap();
                
                let mut items = <(Entity, &Item, &Point)>::query();
                items.iter(ecs)
                    .filter(|(_entity, _item, &item_pos)| item_pos == player_pos)
                    .for_each(|(entity, _item, _item_pos)|{
                        commands.remove_component::<Point>(*entity);
                        commands.add_component(*entity, Carried(player));

                        //weapon pick up
                        if let Ok(e) = ecs.entry_ref(*entity){
                            if e.get_component::<Weapon>().is_ok(){
                                <(Entity, &Carried, &Weapon)>::query()
                                .iter(ecs)
                                .filter(|(_,c,_)|c.0 == player)
                                .for_each(|(e,c,w)|{
                                    commands.remove(*e);
                                })
                            }
                        }
                    }
                );
                Point::new(0,0)
            },
            VirtualKeyCode::Key1 => use_item(0, ecs, commands),
            VirtualKeyCode::Key2 => use_item(1, ecs, commands),
            VirtualKeyCode::Key3 => use_item(2, ecs, commands),
            VirtualKeyCode::Key4 => use_item(3, ecs, commands),
            VirtualKeyCode::Key5 => use_item(4, ecs, commands),
            VirtualKeyCode::Key6 => use_item(5, ecs, commands),
            VirtualKeyCode::Key7 => use_item(6, ecs, commands),
            VirtualKeyCode::Key8 => use_item(7, ecs, commands),
            VirtualKeyCode::Key9 => use_item(8, ecs, commands),
            _ => Point::new(0,0),
        };
        let (player_entity, destination) = players
                .iter(ecs)
                .find_map(|(entity, pos)| Some((*entity, *pos + delta)))
                .unwrap();
        
        let mut enemies = <(Entity, &Point)>::query()
            .filter(component::<Enemy>());

        let mut did_something = false;
        if delta.x != 0 || delta.y != 0 {
            let mut hit_something = false;
            enemies
                .iter(ecs)
                .filter(|(_, pos)|{
                    **pos == destination
                })
                .for_each(|(entity, _)|{
                    hit_something = true;
                    did_something = true;
                    //println!("Player attacked");
                    commands
                        .push(((), WantsToAttack{
                            attacker: player_entity,
                            victim: *entity,
                        }));
                });
            
            if !hit_something{
                did_something = true;
                //println!("Player moved");
                commands
                    .push(((), WantsToMove{
                        entity:player_entity,
                        destination,
                    }));
            }
            
        }


        /*if !did_something{
            if let Ok(mut health) = ecs
                .entry_mut(player_entity)
                .unwrap()
                .get_component_mut::<Health>()
            {
                health.current = i32::min(health.max, health.current +1);
            }
            //println!("Player didn't do anything");
        }*/

        *turn_state = TurnState::MonsterTurn;
        
        
        /*
        if delta.x != 0 || delta.y != 0{
            //query for tuple where tag is "Player" 
            //modifies the "Point" component of the tuple
            //the player is inserted first into the world "ecs"
            //by the spawner
            let mut players = <&mut Point>::query()
                .filter(component::<Player>());
            players.iter_mut(ecs).for_each(|pos|{
                let destination = *pos + delta;
                if map.can_enter_tile(destination) {
                    *pos = destination;
                    camera.on_player_move(destination);
                    *turn_state = TurnState::MonsterTurn;
                }
            })
        }*/
    }
}

fn use_item(n: usize, ecs: &mut SubWorld, commands: &mut CommandBuffer) -> Point {
    let player_entity = <(Entity, &Player)>::query()
                        .iter(ecs)
                        .find_map(|(entity,_player)| Some (*entity))
                        .unwrap();
    
    let item_entity = <(Entity, &Item, &Carried)>::query()
                        .iter(ecs)
                        .filter(|(_,_, carried)| carried.0 == player_entity)
                        .enumerate()
                        .filter(|(item_count, (_,_,_))| *item_count == n)
                        .find_map(|(_, (item_entity, _ , _))| Some(*item_entity));
    
    if let Some(item_entity) = item_entity {
        commands    
                .push(((), ActivateItem{
                    used_by: player_entity,
                    item: item_entity
                }));
    }

    Point::zero()
}