Documentation
use crate::hash::HashMap

/**
 * The RemovedState struct represents the state of removed actors, entities, and components.
 */
struct RemovedState {
    actors: HashMap<String, bool>,
    entities: Vec<String>,
    components: HashMap<String, HashMap<String, bool>>,
}

/**
 * The UpdatedState struct represents the state of updated components.
 */
struct UpdatedState {
    components: HashMap<String, HashMap<String, bool>>,
}

/**
 * The CreatedState struct represents the state of created actors, entities, components, and inputs.
 */
struct CreatedState {
    actors: HashMap<String, bool>,
    entities: Vec<String>,
    components: HashMap<String, HashMap<String, bool>>,
    inputs: HashMap<String, Vec<i32>>,
}

/**
 * The PendingContext struct represents the context of pending operations.
 */
struct PendingContext {
    pending: Option<Pending>,
}

/**
 * The Pending struct represents a pending state with removed, updated, and created states.
 */
struct Pending {
    removed: RemovedState,
    updated: UpdatedState,
    created: CreatedState,
}

impl Pending {
    /**
     * Constructs a new Pending object and resets its state.
     */
    fn new() -> Self {
        Self {
            removed: RemovedState {
                actors: HashMap::new(),
                entities: Vec::new(),
                components: HashMap::new(),
            },
            updated: UpdatedState {
                components: HashMap::new(),
            },
            created: CreatedState {
                actors: HashMap::new(),
                entities: Vec::new(),
                components: HashMap::new(),
                inputs: HashMap::new(),
            },
        }
    }

    /**
     * Adds an actor input to the created inputs state.
     *
     * @param {String} id - The ID of the actor.
     * @param {i32} newindex - The index of the new input.
     */
    fn actor_input(&mut self, id: String, newindex: i32) {
        self.created.inputs.entry(id).or_insert(Vec::new()).push(newindex);
    }

    /**
     * Changes a component in the specified pending state.
     *
     * @param {String} pending_type - The type of the pending state (removed, updated, or created).
     * @param {String} id - The ID of the entity.
     * @param {String} key - The key of the component.
     */
    fn change_component(&mut self, pending_type: String, id: String, key: String) {
        self.upsert_component(pending_type, id, key);
    }

    /**
     * Marks an entity as created in the created state.
     *
     * @param {String} id - The ID of the entity to create.
     */
    fn create_entity(&mut self, id: String) {
        self.created.entities.push(id);
    }

    /**
     * Marks an actor as removed in the removed state.
     *
     * @param {String} id - The ID of the actor to remove.
     */
    fn remove_actor(&mut self, id: String) {
        self.removed.actors.insert(id, true);
    }

    /**
     * Marks a component as removed in the removed state.
     *
     * @param {String} id - The ID of the entity.
     * @param {String} key - The key of the component to remove.
     */
    fn remove_component(&mut self, id: String, key: String) {
        self.removed.components.entry(id).or_insert(HashMap::new()).insert(key, true);
    }

    /**
     * Marks an entity as removed in the removed state.
     *
     * @param {String} id - The ID of the entity to remove.
     */
    fn remove_entity(&mut self, id: String) {
        self.removed.entities.push(id);
    }

    /**
     * Resets the state of the Pending object.
     */
    fn reset(&mut self) {
        *self = Self::new();
    }

    /**
     * Marks an actor as spawned in the created state.
     *
     * @param {String} id - The ID of the actor to spawn.
     */
    fn spawn_actor(&mut self, id: String) {
        self.created.actors.insert(id, true);
    }

    /**
     * Inserts or updates a component in the specified pending state.
     *
     * @param {String} pending_type - The type of the pending state (created or updated).
     * @param {String} id - The ID of the entity.
     * @param {String} key - The key of the component.
     */
    fn upsert_component(&mut self, pending_type: String, id: String, key: String) {
        let pending = if pending_type == "created" {
            &mut self.created
        } else {
            &mut self.updated
        };

        if let Some(components) = pending.components.get_mut(&id) {
            components.insert(key, true);
        } else {
            let mut new_components = HashMap::new();
            new_components.insert(key, true);
            pending.components.insert(id, new_components);
        }
    }
}

/**
 * The withPending struct contains a pending state and methods for managing it.
 */
struct WithPending {
    pending: Pending,
}

impl WithPending {
    /**
     * Constructs a new WithPending object.
     *
     * @param {PendingContext} context - The context for the pending state.
     */
    fn new(context: ContextWithPending | ContextWithPendingAndSymbols) -> Self {
        let pending = context.pending.unwrap_or_else(|| Pending::new());
        Self { pending }
    }

    /**
     * Resets the current pending state.
     */
    fn reset_pending(&mut self) {
        self.pending.reset();
    }
}

/**
 * The PendingWithSymbols struct extends the Pending struct with symbol management.
 */
struct PendingWithSymbols {
    pending: Pending,
    symbols: Vec<(String, i32)>,
}

impl PendingWithSymbols {
    /**
     * Constructs a new PendingWithSymbols object and initializes its symbols array.
     */
    fn new() -> Self {
        Self {
            pending: Pending::new(),
            symbols: Vec::new(),
        }
    }

    /**
     * Adds a symbol tuple to the symbols array.
     *
     * @param {String} symbol_tuple - The symbol tuple to add.
     */
    fn add_symbol(&mut self, symbol_tuple: (String, i32)) {
        self.symbols.push(symbol_tuple);
    }

    /**
     * Replaces the symbols array with a new array of symbol tuples.
     *
     * @param {Vec<(String, i32)>} symbols - The new array of symbols.
     */
    fn replace_symbols(&mut self, symbols: Vec<(String, i32)>) {
        self.symbols = symbols;
    }
}

fn main() {
    let pending_with_symbols = PendingWithSymbols::new();
}