use std::path::PathBuf;

use bevy::prelude::*;
use shared::{
    ActorId, ActorKind, ActorName, AnimationControllerDesc, AudioListenerDesc, AudioSourceDesc,
    AuthoringComponentStates, BrushDesc, ColliderDesc, EditorVisibility, InspectorOrder, LightDesc,
    MaterialDesc, MaterialOverride, ModelRef, NavigationArea, NavigationBounds, NavigationLink,
    NavigationObstacle, ObjectiveMarker, PhysicsBody, PostProcessVolumeDesc, PrefabInstance,
    PrefabRef, Primitive, RigidBodyDesc, SceneComposition, SkinnedMeshRenderer, StaticMeshRenderer,
    TeamSpawn, TriggerVolume, WeaponSpawn,
};
#[derive(Debug, Clone)]
pub struct EditorEntitySnapshot {
    pub actor_id: Option<ActorId>,
    pub actor_kind: ActorKind,
    pub actor_name: Option<ActorName>,
    pub name: Option<String>,
    pub transform: Transform,
    pub primitive: Option<Primitive>,
    pub brush: Option<BrushDesc>,
    pub static_mesh_renderer: Option<StaticMeshRenderer>,
    pub skinned_mesh_renderer: Option<SkinnedMeshRenderer>,
    pub material: Option<MaterialDesc>,
    pub material_override: Option<MaterialOverride>,
    pub rigid_body: Option<RigidBodyDesc>,
    pub collider: Option<ColliderDesc>,
    pub physics: Option<PhysicsBody>,
    pub light: Option<LightDesc>,
    pub animation_controller: Option<AnimationControllerDesc>,
    pub audio_source: Option<AudioSourceDesc>,
    pub audio_listener: Option<AudioListenerDesc>,
    pub player_spawn: bool,
    pub model: Option<ModelRef>,
    pub prefab: Option<PrefabRef>,
    pub prefab_instance: Option<PrefabInstance>,
    pub weapon_spawn: Option<WeaponSpawn>,
    pub trigger_volume: Option<TriggerVolume>,
    pub post_process_volume: Option<PostProcessVolumeDesc>,
    pub team_spawn: Option<TeamSpawn>,
    pub objective: Option<ObjectiveMarker>,
    pub navigation_bounds: Option<NavigationBounds>,
    pub navigation_obstacle: Option<NavigationObstacle>,
    pub navigation_area: Option<NavigationArea>,
    pub navigation_link: Option<NavigationLink>,
    pub hierarchy_sibling_index: i32,
    pub editor_visibility: EditorVisibility,
    pub inspector_order: Option<InspectorOrder>,
    pub component_states: Option<AuthoringComponentStates>,
    pub children: Vec<EditorEntitySnapshot>,
}

/// One reflected component value used by registry-driven editor transactions.
/// `component_id` is stable; `type_path` is retained only to resolve Bevy's
/// reflection adapter for this build.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReflectedComponentValue {
    pub component_id: String,
    pub type_path: String,
    pub ron: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ComponentDelta {
    pub component_id: String,
    pub type_path: String,
    pub before: Option<ReflectedComponentValue>,
    pub after: Option<ReflectedComponentValue>,
}

/// An atomic add/remove/reset/paste operation. Requirements, dependent removals,
/// and the derived ActorKind hint can be represented as additional deltas.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ComponentTransaction {
    pub entity: Entity,
    pub label: &'static str,
    pub deltas: Vec<ComponentDelta>,
}

#[derive(Debug, Clone, Default, PartialEq)]
pub struct NavigationComponentState {
    pub bounds: Option<NavigationBounds>,
    pub obstacle: Option<NavigationObstacle>,
    pub area: Option<NavigationArea>,
    pub link: Option<NavigationLink>,
}

#[derive(Debug, Clone)]
pub struct SiblingChange {
    pub entity: Entity,
    pub old_parent: Option<Entity>,
    pub new_parent: Option<Entity>,
    pub old_index: i32,
    pub new_index: i32,
    pub old_transform: Option<Transform>,
    pub new_transform: Option<Transform>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct PrefabEditState {
    pub instance: Option<PrefabInstance>,
    pub prefab_ref: Option<PrefabRef>,
    pub blocked_reason: Option<String>,
    pub transform: Option<Transform>,
    pub material: Option<MaterialDesc>,
}

#[derive(Debug, Clone)]
pub enum EditorCommand {
    Spawn {
        snapshot: EditorEntitySnapshot,
        entity: Option<Entity>,
    },
    SpawnMany {
        snapshots: Vec<EditorEntitySnapshot>,
        entities: Vec<Entity>,
    },
    Despawn {
        snapshot: EditorEntitySnapshot,
        entity: Option<Entity>,
    },
    Duplicate {
        snapshots: Vec<EditorEntitySnapshot>,
        entities: Vec<Entity>,
    },
    Rename {
        entity: Entity,
        old: String,
        new: String,
    },
    SetTransform {
        entity: Entity,
        old: Transform,
        new: Transform,
    },
    SetMaterial {
        entity: Entity,
        old: Option<MaterialDesc>,
        new: MaterialDesc,
    },
    SetMaterialGroup {
        entities: Vec<Entity>,
        olds: Vec<Option<MaterialDesc>>,
        news: Vec<MaterialDesc>,
    },
    SetMaterialOverride {
        entity: Entity,
        old: Option<MaterialOverride>,
        new: MaterialOverride,
    },
    SetLight {
        entity: Entity,
        old: Option<LightDesc>,
        new: LightDesc,
    },
    SetAnimationController {
        entity: Entity,
        old: Option<AnimationControllerDesc>,
        new: AnimationControllerDesc,
    },
    SetAudioSource {
        entity: Entity,
        old: Option<AudioSourceDesc>,
        new: AudioSourceDesc,
    },
    SetAudioListener {
        entity: Entity,
        old: Option<AudioListenerDesc>,
        new: AudioListenerDesc,
    },
    SetPhysics {
        entity: Entity,
        old: Option<PhysicsBody>,
        new: PhysicsBody,
    },
    SetRigidBody {
        entity: Entity,
        old: Option<RigidBodyDesc>,
        new: RigidBodyDesc,
    },
    SetCollider {
        entity: Entity,
        old: Option<ColliderDesc>,
        new: ColliderDesc,
    },
    SetPrimitive {
        entity: Entity,
        old: Option<Primitive>,
        new: Primitive,
    },
    SetBrush {
        entity: Entity,
        old: Option<BrushDesc>,
        new: BrushDesc,
    },
    SetBrushTransform {
        entity: Entity,
        old_transform: Transform,
        new_transform: Transform,
        old_brush: Option<BrushDesc>,
        new_brush: BrushDesc,
    },
    ApplyBrushCsg {
        primary: Entity,
        old_transform: Transform,
        new_transform: Transform,
        old_brush: Option<BrushDesc>,
        new_brush: BrushDesc,
        deleted: Vec<(EditorEntitySnapshot, Option<Entity>)>,
    },
    SetStaticMeshRenderer {
        entity: Entity,
        old: Option<StaticMeshRenderer>,
        new: StaticMeshRenderer,
    },
    SetPostProcessVolume {
        entity: Entity,
        old: Option<PostProcessVolumeDesc>,
        new: PostProcessVolumeDesc,
    },
    SetNavigation {
        entity: Entity,
        old: NavigationComponentState,
        new: NavigationComponentState,
    },
    SetTransformGroup {
        entities: Vec<Entity>,
        olds: Vec<Transform>,
        news: Vec<Transform>,
    },
    Reparent {
        entity: Entity,
        old_parent: Option<Entity>,
        new_parent: Option<Entity>,
    },
    SetActorKind {
        entity: Entity,
        old: ActorKind,
        new: ActorKind,
    },
    ReorderSibling {
        changes: Vec<SiblingChange>,
    },
    SetEditorVisibility {
        entity: Entity,
        old: EditorVisibility,
        new: EditorVisibility,
    },
    SetInspectorOrder {
        entity: Entity,
        old: Option<InspectorOrder>,
        new: InspectorOrder,
    },
    SetSceneComposition {
        old: SceneComposition,
        new: SceneComposition,
    },
    SetPrefabState {
        entity: Entity,
        old: PrefabEditState,
        new: PrefabEditState,
    },
    ApplyPrefabToSource {
        entity: Entity,
        source_path: PathBuf,
        before_source: String,
        after_source: String,
        old: PrefabEditState,
        new: PrefabEditState,
    },
    UnpackPrefab {
        entity: Entity,
        instance: PrefabInstance,
        prefab_ref: PrefabRef,
        linked_actor_kind: ActorKind,
        fully_local: bool,
        linked_local_snapshots: Vec<EditorEntitySnapshot>,
        linked_local_roots: Vec<Entity>,
        unpacked_snapshots: Vec<EditorEntitySnapshot>,
        unpacked_parented_to_anchor: Vec<bool>,
        unpacked_roots: Vec<Entity>,
    },
    AddComponent {
        entity: Entity,
        snapshot: EditorEntitySnapshot,
    },
    RemoveComponent {
        entity: Entity,
        snapshot: EditorEntitySnapshot,
    },
    ComponentTransaction(ComponentTransaction),
}

impl EditorCommand {
    pub fn label(&self) -> &'static str {
        match self {
            EditorCommand::Spawn { .. } => "Spawn",
            EditorCommand::SpawnMany { .. } => "Spawn Brushes",
            EditorCommand::Despawn { .. } => "Delete",
            EditorCommand::Duplicate { .. } => "Duplicate",
            EditorCommand::Rename { .. } => "Rename",
            EditorCommand::SetTransform { .. } => "Move",
            EditorCommand::SetMaterial { .. } => "Set Material",
            EditorCommand::SetMaterialGroup { .. } => "Apply Material to Selection",
            EditorCommand::SetMaterialOverride { .. } => "Set Material Override",
            EditorCommand::SetLight { .. } => "Set Light",
            EditorCommand::SetAnimationController { .. } => "Set Animation Controller",
            EditorCommand::SetAudioSource { .. } => "Set Audio Source",
            EditorCommand::SetAudioListener { .. } => "Set Audio Listener",
            EditorCommand::SetPhysics { .. } => "Set Physics",
            EditorCommand::SetRigidBody { .. } => "Set Rigid Body",
            EditorCommand::SetCollider { .. } => "Set Collider",
            EditorCommand::SetPrimitive { .. } => "Set Primitive",
            EditorCommand::SetBrush { .. } => "Set Brush",
            EditorCommand::SetBrushTransform { .. } => "Clip Brush",
            EditorCommand::ApplyBrushCsg { .. } => "Brush CSG",
            EditorCommand::SetStaticMeshRenderer { .. } => "Set Static Mesh Renderer",
            EditorCommand::SetPostProcessVolume { .. } => "Set Post Process Volume",
            EditorCommand::SetNavigation { .. } => "Set Navigation",
            EditorCommand::SetTransformGroup { .. } => "Move Selection",
            EditorCommand::Reparent { .. } => "Reparent",
            EditorCommand::SetActorKind { .. } => "Set Actor Kind",
            EditorCommand::ReorderSibling { .. } => "Reorder Hierarchy",
            EditorCommand::SetEditorVisibility { .. } => "Set Visibility",
            EditorCommand::SetInspectorOrder { .. } => "Set Component Order",
            EditorCommand::SetSceneComposition { .. } => "Set Scene Composition",
            EditorCommand::SetPrefabState { .. } => "Edit Prefab Instance",
            EditorCommand::ApplyPrefabToSource { .. } => "Apply Prefab to Source",
            EditorCommand::UnpackPrefab {
                fully_local: true, ..
            } => "Convert Prefab to Local",
            EditorCommand::UnpackPrefab {
                fully_local: false, ..
            } => "Unpack Prefab Layer",
            EditorCommand::AddComponent { .. } => "Add Component",
            EditorCommand::RemoveComponent { .. } => "Remove Component",
            EditorCommand::ComponentTransaction(transaction) => transaction.label,
        }
    }
}
