use crate::entity::mob::Mob;
use std::{any::TypeId, ops::BitOr, pin::Pin, ptr};

pub mod active_target;
pub mod ambient_stand;
pub mod avoid_entity;
pub mod beg;
pub mod blaze_attack;
pub mod bow_attack;
pub mod breed;
pub mod chase_player;
pub mod creeper_ignite;
pub mod destroy_egg;
pub mod eat_grass;
pub mod escape_danger;
pub mod follow_owner;
pub mod follow_parent;
pub mod goal_selector;
pub mod look_around;
pub mod look_at_entity;
pub mod melee_attack;
pub mod move_to_target_pos;
pub mod owner_hurt_by_target;
pub mod owner_hurt_target;
pub mod pick_up_block;
pub mod place_block;
pub mod revenge;
pub mod step_and_destroy_block;
pub mod swim;
pub mod teleport_towards_player;
pub mod tempt;
pub(crate) mod track_target;
pub mod wander_around;
pub mod zombie_attack;

#[must_use]
pub const fn to_goal_ticks(server_ticks: i32) -> i32 {
    -(-server_ticks).div_euclid(2)
}

pub type GoalFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

pub trait Goal: Send + Sync {
    /// How should the `Goal` initially start?
    fn can_start<'a>(&'a mut self, _mob: &'a dyn Mob) -> GoalFuture<'a, bool> {
        Box::pin(async { false })
    }

    /// When it's started, how should it continue to run?
    fn should_continue<'a>(&'a self, _mob: &'a dyn Mob) -> GoalFuture<'a, bool> {
        Box::pin(async { false })
    }

    /// Call when goal start
    fn start<'a>(&'a mut self, _: &'a dyn Mob) -> GoalFuture<'a, ()> {
        Box::pin(async {})
    }

    /// Call when goal stop
    fn stop<'a>(&'a mut self, _: &'a dyn Mob) -> GoalFuture<'a, ()> {
        Box::pin(async {})
    }

    /// If the `Goal` is running, this gets called every tick.
    fn tick<'a>(&'a mut self, _: &'a dyn Mob) -> GoalFuture<'a, ()> {
        Box::pin(async {})
    }

    fn should_run_every_tick(&self) -> bool {
        false
    }

    fn can_stop(&self) -> bool {
        true
    }

    fn get_tick_count(&self, ticks: i32) -> i32 {
        if self.should_run_every_tick() {
            ticks
        } else {
            to_goal_ticks(ticks)
        }
    }

    fn controls(&self) -> Controls {
        Controls::empty()
    }
}

#[derive(Clone, Copy, Default)]
// We actually only use the first 4 bits ;)
pub struct Controls(u8);

impl Controls {
    pub const MOVE: Self = Self(1);
    pub const LOOK: Self = Self(2);
    pub const JUMP: Self = Self(4);
    pub const TARGET: Self = Self(8);

    pub const ITER: [Self; 4] = [Self::MOVE, Self::LOOK, Self::JUMP, Self::TARGET];

    #[must_use]
    pub fn empty() -> Self {
        Self::default()
    }

    pub const fn set(&mut self, control: Self, val: bool) {
        if val {
            self.0 |= control.0;
        } else {
            self.0 &= !control.0;
        }
    }

    #[must_use]
    pub const fn get(&self, control: Self) -> bool {
        self.0 & control.0 != 0
    }

    #[must_use]
    pub fn idx(&self) -> usize {
        for (i, control) in Self::ITER.into_iter().enumerate() {
            if self.get(control) {
                return i;
            }
        }
        tracing::error!("Controls::idx called with no controls set");
        0
    }
}

impl BitOr for Controls {
    type Output = Self;
    fn bitor(self, rhs: Self) -> Self::Output {
        Self(self.0 | rhs.0)
    }
}

pub struct PrioritizedGoal {
    pub goal: Box<dyn Goal>,
    pub running: bool,
    pub priority: u8,
    /// Used to compare goals of the same type.
    /// Always set to `TypeId::of::<G>()` where `G: Goal`.
    type_id: TypeId,
}

impl PrioritizedGoal {
    #[must_use]
    pub fn new(type_id: TypeId, priority: u8, goal: Box<dyn Goal>) -> Self {
        Self {
            goal,
            running: false,
            priority,
            type_id,
        }
    }

    fn can_be_replaced_by(&self, goal: &Self) -> bool {
        self.can_stop() && goal.priority < self.priority
    }
}

impl Goal for PrioritizedGoal {
    fn can_start<'a>(&'a mut self, mob: &'a dyn Mob) -> GoalFuture<'a, bool> {
        Box::pin(async { self.goal.can_start(mob).await })
    }

    fn should_continue<'a>(&'a self, mob: &'a dyn Mob) -> GoalFuture<'a, bool> {
        Box::pin(async { self.goal.should_continue(mob).await })
    }

    fn start<'a>(&'a mut self, mob: &'a dyn Mob) -> GoalFuture<'a, ()> {
        Box::pin(async {
            if !self.running {
                self.running = true;
                self.goal.start(mob).await;
            }
        })
    }

    fn stop<'a>(&'a mut self, mob: &'a dyn Mob) -> GoalFuture<'a, ()> {
        Box::pin(async {
            if self.running {
                self.running = false;
                self.goal.stop(mob).await;
            }
        })
    }

    fn tick<'a>(&'a mut self, mob: &'a dyn Mob) -> GoalFuture<'a, ()> {
        Box::pin(async {
            self.goal.tick(mob).await;
        })
    }

    fn should_run_every_tick(&self) -> bool {
        self.goal.should_run_every_tick()
    }

    fn get_tick_count(&self, ticks: i32) -> i32 {
        self.goal.get_tick_count(ticks)
    }

    fn controls(&self) -> Controls {
        self.goal.controls()
    }
}

#[derive(Clone)]
pub struct ParentHandle<P> {
    ptr: *const P,
}

impl<P> ParentHandle<P> {
    /// This wrapper allows a child struct to hold a reference to its parent
    /// without making the code overly verbose.
    ///
    /// # Safety
    /// - The parent must outlive this handle.
    /// - The parent must be inside a smart pointer; otherwise it
    ///   will move in memory and cause undefined behavior!
    ///
    /// # Example
    /// ```
    /// use pumpkin::entity::ai::goal::ParentHandle;
    ///
    /// struct Parent {
    ///     child: Child,
    ///     value: i32
    /// }
    ///
    /// struct Child {
    ///     parent: ParentHandle<Parent>,
    /// }
    ///
    /// impl Child {
    ///    fn value(&self) -> i32 {
    ///        self.parent.get().unwrap().value
    ///    }
    /// }
    ///
    /// let mut parent = Box::new(Parent {
    ///     child: Child {parent: ParentHandle::none()},
    ///     value: 7,
    /// });
    /// parent.child.parent = unsafe { ParentHandle::new(&parent) };
    ///
    /// assert_eq!(parent.child.value(), 7);
    /// ```
    pub const unsafe fn new(parent: &P) -> Self {
        Self {
            ptr: ptr::from_ref(parent),
        }
    }

    #[must_use]
    /// Creates an empty handle (equivalent to `Option::None`).
    // We can use null as None because we handle it in get.
    pub const fn none() -> Self {
        Self { ptr: ptr::null() }
    }

    #[must_use]
    /// Returns a reference to the parent if available.
    /// This will cause undefined behavior if #Safety rules in new aren't followed
    pub const fn get(&self) -> Option<&P> {
        if self.ptr.is_null() {
            None
        } else {
            // SAFETY: `self.ptr` was initialized from a valid reference in `ParentHandle::new` and outlives `ParentHandle`.
            unsafe { Some(&*self.ptr) }
        }
    }
}

impl<P> Default for ParentHandle<P> {
    fn default() -> Self {
        Self::none()
    }
}

// SAFETY: ParentHandle stores a raw pointer `*const P` to parent goal structures managed within the same AI engine instance.
unsafe impl<P> Sync for ParentHandle<P> {}
// SAFETY: ParentHandle stores a raw pointer `*const P` to parent goal structures managed within the same AI engine instance.
unsafe impl<P> Send for ParentHandle<P> {}
