use nightshade::ecs::scene::{AssetUuid, ChunkId, LayerId};
use nightshade::prelude::Entity;
use std::collections::{HashMap, HashSet};

#[derive(Default)]
pub struct EditorScene {
    pub uuid_to_entity: HashMap<AssetUuid, Entity>,
    pub entity_to_uuid: HashMap<Entity, AssetUuid>,
    pub scaffolding: HashSet<Entity>,
    pub entity_layers: HashMap<Entity, LayerId>,
    pub entity_chunks: HashMap<Entity, ChunkId>,
}

impl EditorScene {
    pub fn clear(&mut self) {
        self.uuid_to_entity.clear();
        self.entity_to_uuid.clear();
        self.entity_layers.clear();
        self.entity_chunks.clear();
    }

    pub fn set_entity_layer(&mut self, entity: Entity, layer: Option<LayerId>) {
        match layer {
            Some(layer) => {
                self.entity_layers.insert(entity, layer);
            }
            None => {
                self.entity_layers.remove(&entity);
            }
        }
    }

    pub fn set_entity_chunk(&mut self, entity: Entity, chunk: Option<ChunkId>) {
        match chunk {
            Some(chunk) => {
                self.entity_chunks.insert(entity, chunk);
            }
            None => {
                self.entity_chunks.remove(&entity);
            }
        }
    }

    pub fn entity_layer(&self, entity: Entity) -> Option<LayerId> {
        self.entity_layers.get(&entity).copied()
    }

    pub fn entity_chunk(&self, entity: Entity) -> Option<ChunkId> {
        self.entity_chunks.get(&entity).copied()
    }

    pub fn register_scaffolding(&mut self, entity: Entity) {
        self.scaffolding.insert(entity);
    }

    pub fn unregister_scaffolding(&mut self, entity: Entity) {
        self.scaffolding.remove(&entity);
    }

    pub fn is_scaffolding(&self, entity: Entity) -> bool {
        self.scaffolding.contains(&entity)
    }

    pub fn replace_entities(&mut self, uuid_to_entity: HashMap<AssetUuid, Entity>) {
        self.entity_to_uuid = uuid_to_entity
            .iter()
            .map(|(uuid, entity)| (*entity, *uuid))
            .collect();
        self.uuid_to_entity = uuid_to_entity;
        self.entity_layers.clear();
        self.entity_chunks.clear();
    }

    pub fn insert(&mut self, uuid: AssetUuid, entity: Entity) {
        self.uuid_to_entity.insert(uuid, entity);
        self.entity_to_uuid.insert(entity, uuid);
    }

    pub fn remove_entity(&mut self, entity: Entity) -> Option<AssetUuid> {
        let uuid = self.entity_to_uuid.remove(&entity)?;
        self.uuid_to_entity.remove(&uuid);
        self.entity_layers.remove(&entity);
        self.entity_chunks.remove(&entity);
        Some(uuid)
    }

    pub fn uuid_for(&self, entity: Entity) -> Option<AssetUuid> {
        self.entity_to_uuid.get(&entity).copied()
    }

    pub fn entity_for(&self, uuid: AssetUuid) -> Option<Entity> {
        self.uuid_to_entity.get(&uuid).copied()
    }

    pub fn known_entities(&self) -> impl Iterator<Item = Entity> + '_ {
        self.entity_to_uuid.keys().copied()
    }
}
