/**
 * Scope filter — decides which entities are relevant to which peer.
 *
 * Interface (duck-typed):
 * ```
 *   {
 *     is_entity_in_scope(peer_id: number, entity_id: number): boolean
 *   }
 * ```
 *
 * Used by the {@link Replicator} to skip actions that touch only
 * out-of-scope entities for a given peer (e.g. PVS culling, distance-based
 * area-of-interest, faction-based visibility).
 *
 * The framework ships {@link AlwaysRelevantScope} as a "send everything to
 * everyone" default. Production games supply their own implementation.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class AlwaysRelevantScope {
    is_entity_in_scope(_peer_id, _network_id) {
        return true;
    }
}

/**
 * Scope filter that excludes entities whose `NetworkIdentity.owner_peer_id`
 * matches the recipient peer.
 *
 * Use on the server side when client-side prediction is in play: the server
 * should NOT echo client-owned-entity actions back to that client over the
 * action stream, otherwise the executor would re-apply them on top of the
 * client's prediction. Authoritative state for those entities goes via the
 * out-of-band {@link NetworkPeer#send_auth_state} channel instead.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class OwnerAwareScope {

    /**
     * @param {{
     *   world: EntityComponentDataset,
     *   slot_table: ReplicationSlotTable,
     *   identity_class: Function,
     * }} options
     *   `identity_class` is the component class that carries the
     *   `owner_peer_id` field — typically `NetworkIdentity`. Passed as a
     *   parameter rather than imported so this helper stays in the
     *   transport-agnostic `replication/` layer.
     */
    constructor({ world, slot_table, identity_class }) {
        this.world = world;
        this.slot_table = slot_table;
        this.identity_class = identity_class;
    }

    /**
     * @param {number} peer_id recipient
     * @param {number} network_id the entity in question
     * @returns {boolean} true if the entity should be sent to this peer
     */
    is_entity_in_scope(peer_id, network_id) {
        const local_e = this.slot_table.entity_for(network_id);
        if (local_e < 0) return true; // unknown locally; defer to receiver
        const id = this.world.getComponent(local_e, this.identity_class);
        if (id === undefined) return true;
        return id.owner_peer_id !== peer_id;
    }
}
