use std::{cell::RefCell, rc::Rc};

use proto::ProtEntityType;

use crate::entity::Entity;

pub struct Visitor {
    visitor_type: VisitorType,
    visitor_entity: Rc<RefCell<dyn Entity>>,
    entity_vec: Vec<Rc<RefCell<dyn Entity>>>,
}

pub enum VisitorType {
    Entity,
    // Gather,
    // Authority,
}

impl Visitor {
    pub fn new(visitor_type: VisitorType, entity: Rc<RefCell<dyn Entity>>) -> Self {
        Self {
            visitor_type,
            visitor_entity: entity,
            entity_vec: Vec::new(),
        }
    }

    pub fn visit_entity(&mut self, entity: &Rc<RefCell<dyn Entity>>) {
        if self.can_add_entity(entity) {
            self.entity_vec.push(entity.clone());
        }
    }

    pub fn get_entity_vec(&self) -> &Vec<Rc<RefCell<dyn Entity>>> {
        &self.entity_vec
    }

    fn can_add_entity(&self, entity: &Rc<RefCell<dyn Entity>>) -> bool {
        match self.visitor_type {
            VisitorType::Entity => {
                let visitor_entity_type = self.visitor_entity.borrow().get_entity_type();
                let entity_type = entity.borrow().get_entity_type();

                if entity_type == ProtEntityType::ProtEntityEyePoint {
                    if visitor_entity_type != ProtEntityType::ProtEntityAvatar
                        && visitor_entity_type != ProtEntityType::ProtEntityEyePoint
                    {
                        return true;
                    }
                }

                if entity_type > ProtEntityType::ProtEntityEyePoint
                    || entity_type == ProtEntityType::ProtEntityWeather
                {
                    return false;
                }
            }
        }

        entity.borrow().entity_id() != self.visitor_entity.borrow().entity_id()
    }
}
