//! Public types for resolved Storybook entities
//!
//! These types represent fully resolved, validated entities after the
//! resolution pipeline completes. Unlike the AST types which represent
//! raw parsed syntax, these types:
//! - Have all cross-references resolved
//! - Have all overrides applied
//! - Have passed semantic validation
//! - Are ready for consumption by the game engine

use std::collections::HashMap;

use crate::syntax::ast::{
    BehaviorLink,
    BehaviorNode,
    Participant,
    ProseBlock,
    Span,
    Time,
    Transition,
    Value,
};

/// A fully resolved Storybook project
#[derive(Debug, Clone)]
pub struct ResolvedFile {
    pub declarations: Vec<ResolvedDeclaration>,
}

/// A resolved top-level declaration
#[derive(Debug, Clone)]
pub enum ResolvedDeclaration {
    Character(ResolvedCharacter),
    Template(ResolvedTemplate),
    LifeArc(ResolvedLifeArc),
    Schedule(ResolvedSchedule),
    Behavior(ResolvedBehavior),
    Institution(ResolvedInstitution),
    Relationship(ResolvedRelationship),
    Location(ResolvedLocation),
    Species(ResolvedSpecies),
}

/// A character with all templates applied and references resolved
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedCharacter {
    pub name: String,
    pub species: Option<String>,
    pub fields: HashMap<String, Value>,
    pub prose_blocks: HashMap<String, ProseBlock>,
    pub uses_behaviors: Option<Vec<BehaviorLink>>,
    pub uses_schedule: Option<Vec<String>>,
    pub span: Span,
}

/// A template definition (before instantiation)
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedTemplate {
    pub name: String,
    pub fields: HashMap<String, Value>,
    pub span: Span,
}

/// A life arc with validated state transitions
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedLifeArc {
    pub name: String,
    pub states: Vec<ResolvedArcState>,
    pub span: Span,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedArcState {
    pub name: String,
    pub transitions: Vec<Transition>,
    pub span: Span,
}

/// A schedule with validated non-overlapping blocks
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedSchedule {
    pub name: String,
    pub blocks: Vec<ResolvedScheduleBlock>,
    pub span: Span,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedScheduleBlock {
    pub activity: String,
    pub start: Time,
    pub end: Time,
    pub span: Span,
}

/// A behavior tree with validated actions
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedBehavior {
    pub name: String,
    pub root: BehaviorNode,
    pub span: Span,
}

/// An institution with resolved member references
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedInstitution {
    pub name: String,
    pub fields: HashMap<String, Value>,
    pub span: Span,
}

/// A bidirectional relationship with merged self/other blocks
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedRelationship {
    pub name: String,
    pub participants: Vec<Participant>,
    pub fields: HashMap<String, Value>,
    pub span: Span,
}

/// A location definition
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedLocation {
    pub name: String,
    pub fields: HashMap<String, Value>,
    pub span: Span,
}

/// A species definition
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedSpecies {
    pub name: String,
    pub fields: HashMap<String, Value>,
    pub span: Span,
}

impl ResolvedFile {
    /// Get all characters in the file
    pub fn characters(&self) -> impl Iterator<Item = &ResolvedCharacter> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::Character(c) => Some(c),
            | _ => None,
        })
    }

    /// Get all relationships in the file
    pub fn relationships(&self) -> impl Iterator<Item = &ResolvedRelationship> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::Relationship(r) => Some(r),
            | _ => None,
        })
    }

    /// Get all institutions in the file
    pub fn institutions(&self) -> impl Iterator<Item = &ResolvedInstitution> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::Institution(i) => Some(i),
            | _ => None,
        })
    }

    /// Get all schedules in the file
    pub fn schedules(&self) -> impl Iterator<Item = &ResolvedSchedule> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::Schedule(s) => Some(s),
            | _ => None,
        })
    }

    /// Get all behavior trees in the file
    pub fn behaviors(&self) -> impl Iterator<Item = &ResolvedBehavior> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::Behavior(b) => Some(b),
            | _ => None,
        })
    }

    /// Get all life arcs in the file
    pub fn life_arcs(&self) -> impl Iterator<Item = &ResolvedLifeArc> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::LifeArc(la) => Some(la),
            | _ => None,
        })
    }

    /// Get all locations in the file
    pub fn locations(&self) -> impl Iterator<Item = &ResolvedLocation> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::Location(l) => Some(l),
            | _ => None,
        })
    }

    /// Get all species in the file
    pub fn species(&self) -> impl Iterator<Item = &ResolvedSpecies> {
        self.declarations.iter().filter_map(|decl| match decl {
            | ResolvedDeclaration::Species(s) => Some(s),
            | _ => None,
        })
    }

    /// Find a character by name
    pub fn find_character(&self, name: &str) -> Option<&ResolvedCharacter> {
        self.characters().find(|c| c.name == name)
    }

    /// Find a relationship by name
    pub fn find_relationship(&self, name: &str) -> Option<&ResolvedRelationship> {
        self.relationships().find(|r| r.name == name)
    }

    /// Find an institution by name
    pub fn find_institution(&self, name: &str) -> Option<&ResolvedInstitution> {
        self.institutions().find(|i| i.name == name)
    }
}
