/// Source location for error reporting with line/column information
#[derive(Debug, Clone, PartialEq)]
pub struct Span {
    pub start: usize,
    pub end: usize,
    pub start_line: usize, // 0-indexed line number
    pub start_col: usize,  // 0-indexed column number
    pub end_line: usize,
    pub end_col: usize,
}

impl Span {
    pub fn new(start: usize, end: usize) -> Self {
        Self {
            start,
            end,
            start_line: 0,
            start_col: 0,
            end_line: 0,
            end_col: 0,
        }
    }

    pub fn with_position(
        start: usize,
        end: usize,
        start_line: usize,
        start_col: usize,
        end_line: usize,
        end_col: usize,
    ) -> Self {
        Self {
            start,
            end,
            start_line,
            start_col,
            end_line,
            end_col,
        }
    }

    /// Convert to LSP Position for the start
    pub fn start_position(&self) -> (u32, u32) {
        (self.start_line as u32, self.start_col as u32)
    }

    /// Convert to LSP Position for the end
    pub fn end_position(&self) -> (u32, u32) {
        (self.end_line as u32, self.end_col as u32)
    }
}

/// Top-level file containing multiple declarations
#[derive(Debug, Clone, PartialEq)]
pub struct File {
    pub declarations: Vec<Declaration>,
}

/// Any top-level declaration
#[derive(Debug, Clone, PartialEq)]
pub enum Declaration {
    Use(UseDecl),
    Character(Character),
    Template(Template),
    LifeArc(LifeArc),
    Schedule(Schedule),
    Behavior(Behavior),
    Institution(Institution),
    Relationship(Relationship),
    Location(Location),
    Species(Species),
    Concept(ConceptDecl),
    SubConcept(SubConceptDecl),
    Definition(DefinitionDecl),
}

/// Use statement for importing definitions
#[derive(Debug, Clone, PartialEq)]
pub struct UseDecl {
    pub path: Vec<String>,
    pub kind: UseKind,
    pub span: Span,
}

#[derive(Debug, Clone, PartialEq)]
pub enum UseKind {
    Single,               // use foo::bar
    Grouped(Vec<String>), // use foo::{bar, baz}
    Wildcard,             // use foo::*
}

/// Link to a behavior tree with optional conditions and priority
#[derive(Debug, Clone, PartialEq)]
pub struct BehaviorLink {
    pub tree: Vec<String>,       // Qualified path to behavior tree
    pub condition: Option<Expr>, // Optional when clause
    pub priority: Priority,      // Execution priority
    pub span: Span,
}

/// Priority levels for behavior selection
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Priority {
    Low,
    Normal,
    High,
    Critical,
}

impl std::str::FromStr for Priority {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            | "low" => Ok(Priority::Low),
            | "normal" => Ok(Priority::Normal),
            | "high" => Ok(Priority::High),
            | "critical" => Ok(Priority::Critical),
            | _ => Err(()),
        }
    }
}

/// Character definition
#[derive(Debug, Clone, PartialEq)]
pub struct Character {
    pub name: String,
    pub species: Option<String>, // `: Species` - what the character fundamentally is
    pub fields: Vec<Field>,
    pub template: Option<Vec<String>>, // `from Template1, Template2`
    pub uses_behaviors: Option<Vec<BehaviorLink>>, // `uses behaviors: [...]`
    pub uses_schedule: Option<Vec<String>>, /* `uses schedule: ScheduleName` or `uses schedules:
                                        * [...]` */
    pub span: Span,
}

/// Template definition (like Character but allows range values)
#[derive(Debug, Clone, PartialEq)]
pub struct Template {
    pub name: String,
    pub species_base: Option<String>, // `: Species` - type constraint from species
    pub fields: Vec<Field>,
    pub strict: bool,
    pub includes: Vec<String>,
    pub uses_behaviors: Option<Vec<BehaviorLink>>, // `uses behaviors: [...]`
    pub uses_schedule: Option<Vec<String>>,        /* `uses schedule: ScheduleName` or `uses
                                                    * schedules: [...]` */
    pub span: Span,
}

/// Field in a structured definition
#[derive(Debug, Clone, PartialEq)]
pub struct Field {
    pub name: String,
    pub value: Value,
    pub span: Span,
}

/// Field value types
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Number(i64),
    Decimal(f64),
    Text(String),
    Boolean(bool),
    Range(Box<Value>, Box<Value>), // For templates: 20..40
    Time(Time),
    Duration(Duration),
    Identifier(Vec<String>), // Qualified path reference
    List(Vec<Value>),
    Object(Vec<Field>),
    ProseBlock(ProseBlock),
    Override(Override),
    Any, // Special marker for type system - matches any value
}

/// Time literal (HH:MM or HH:MM:SS)
#[derive(Debug, Clone, PartialEq)]
pub struct Time {
    pub hour: u8,
    pub minute: u8,
    pub second: u8,
}

/// Duration literal (e.g., 2h30m)
#[derive(Debug, Clone, PartialEq)]
pub struct Duration {
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
}

/// Prose block with tag
#[derive(Debug, Clone, PartialEq)]
pub struct ProseBlock {
    pub tag: String,
    pub content: String,
    pub span: Span,
}

/// Override specification for template instantiation
#[derive(Debug, Clone, PartialEq)]
pub struct Override {
    pub base: Vec<String>, // Template path
    pub overrides: Vec<OverrideOp>,
    pub span: Span,
}

#[derive(Debug, Clone, PartialEq)]
pub enum OverrideOp {
    Set(Field),     // field: value
    Remove(String), // remove field
    Append(Field),  // append field
}

/// Life arc state machine
#[derive(Debug, Clone, PartialEq)]
pub struct LifeArc {
    pub name: String,
    pub required_fields: Vec<FieldRequirement>,
    pub states: Vec<ArcState>,
    pub span: Span,
}

/// A required field declaration in a life arc
#[derive(Debug, Clone, PartialEq)]
pub struct FieldRequirement {
    pub name: String,
    pub type_name: String,
    pub span: Span,
}

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

#[derive(Debug, Clone, PartialEq)]
pub struct Transition {
    pub to: String,
    pub condition: Expr,
    pub span: Span,
}

/// Schedule definition with composition support
#[derive(Debug, Clone, PartialEq)]
pub struct Schedule {
    pub name: String,
    pub modifies: Option<String>, // Base schedule to modify
    pub blocks: Vec<ScheduleBlock>,
    pub recurrences: Vec<RecurrencePattern>, // Recurring events
    pub fields: Vec<Field>,                  // Documentation prose blocks, metadata
    pub span: Span,
}

/// A time block in a schedule
#[derive(Debug, Clone, PartialEq)]
pub struct ScheduleBlock {
    pub name: Option<String>, // Block name for override system
    pub is_override: bool,    // Whether this block overrides a base block
    pub start: Time,
    pub end: Time,
    pub activity: String, // DEPRECATED: kept for backward compatibility
    pub action: Option<Vec<String>>, // Behavior reference (new way)
    pub temporal_constraint: Option<TemporalConstraint>, // When this block applies
    pub fields: Vec<Field>,
    pub span: Span,
}

/// Temporal constraint for when a schedule block applies
#[derive(Debug, Clone, PartialEq)]
pub enum TemporalConstraint {
    Season(String),            // Applies during specific season (enum value)
    DayOfWeek(String),         // Applies on specific day of week (enum value)
    Month(String),             // Applies during specific month (enum value)
    DateRange(String, String), // Applies between two dates (TODO: date type)
}

/// Recurring event pattern
#[derive(Debug, Clone, PartialEq)]
pub struct RecurrencePattern {
    pub name: String,                   // Event name (e.g., "MarketDay")
    pub constraint: TemporalConstraint, // When it recurs (e.g., "on Earthday")
    pub blocks: Vec<ScheduleBlock>,     // What happens during the event
    pub span: Span,
}

// ===== Parser Helper Types for Schedules =====

/// Helper for parsing schedule bodies with flexible ordering
#[derive(Debug, Clone, PartialEq)]
pub enum ScheduleBodyItem {
    Field(Field),
    Block(ScheduleBlock),
    Recurrence(RecurrencePattern),
}

/// Helper for parsing schedule block content
#[derive(Debug, Clone, PartialEq)]
pub enum BlockContentItem {
    TimeRange(Time, Time),
    Field(Field),
}

/// Behavior tree definition
#[derive(Debug, Clone, PartialEq)]
pub struct Behavior {
    pub name: String,
    pub root: BehaviorNode,
    pub span: Span,
}

#[derive(Debug, Clone, PartialEq)]
pub enum BehaviorNode {
    Selector {
        label: Option<String>,
        children: Vec<BehaviorNode>,
    },
    Sequence {
        label: Option<String>,
        children: Vec<BehaviorNode>,
    },
    Condition(Expr),
    Action(String, Vec<Field>), // Action name + parameters
    Decorator {
        decorator_type: DecoratorType,
        child: Box<BehaviorNode>,
    },
    SubTree(Vec<String>), // Reference to another behavior
}

#[derive(Debug, Clone, PartialEq)]
pub enum DecoratorType {
    Repeat,                // infinite loop
    RepeatN(u32),          // N times
    RepeatRange(u32, u32), // min..max times
    Invert,
    Retry(u32),       // max attempts
    Timeout(String),  // duration string (e.g., "5s", "30m", "2h")
    Cooldown(String), // duration string (e.g., "5s", "30m", "2h")
    If(Expr),
    SucceedAlways,
    FailAlways,
}

// BehaviorDuration is used for decorator timeouts/cooldowns (single unit)
// whereas Duration (above) is for general time literals (compound: 2h30m)
#[derive(Debug, Clone, PartialEq)]
pub struct BehaviorDuration {
    pub value: u32,
    pub unit: DurationUnit,
}

#[derive(Debug, Clone, PartialEq)]
pub enum DurationUnit {
    Days,
    Hours,
    Minutes,
    Seconds,
}

impl BehaviorDuration {
    pub fn to_milliseconds(&self) -> u64 {
        let base_ms = self.value as u64;
        match self.unit {
            | DurationUnit::Days => base_ms * 24 * 60 * 60 * 1000,
            | DurationUnit::Hours => base_ms * 60 * 60 * 1000,
            | DurationUnit::Minutes => base_ms * 60 * 1000,
            | DurationUnit::Seconds => base_ms * 1000,
        }
    }
}

/// Institution definition
#[derive(Debug, Clone, PartialEq)]
pub struct Institution {
    pub name: String,
    pub fields: Vec<Field>,
    pub uses_behaviors: Option<Vec<BehaviorLink>>, // `uses behaviors: [...]`
    pub uses_schedule: Option<Vec<String>>,        /* `uses schedule: ScheduleName` or `uses
                                                    * schedules: [...]` */
    pub span: Span,
}

/// Relationship definition
#[derive(Debug, Clone, PartialEq)]
pub struct Relationship {
    pub name: String,
    pub participants: Vec<Participant>,
    pub fields: Vec<Field>,
    pub span: Span,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Participant {
    pub name: Vec<String>,    // Qualified path
    pub role: Option<String>, // "as parent" (optional)
    pub fields: Vec<Field>,   // Participant-specific fields (required block)
    pub span: Span,
}

/// Location definition
#[derive(Debug, Clone, PartialEq)]
pub struct Location {
    pub name: String,
    pub fields: Vec<Field>,
    pub span: Span,
}

/// Species definition
#[derive(Debug, Clone, PartialEq)]
pub struct Species {
    pub name: String,
    pub includes: Vec<String>,
    pub fields: Vec<Field>,
    pub span: Span,
}

/// Concept declaration - base type definition
#[derive(Debug, Clone, PartialEq)]
pub struct ConceptDecl {
    pub name: String,
    pub span: Span,
}

/// Sub-concept declaration - enum or record subtype
#[derive(Debug, Clone, PartialEq)]
pub struct SubConceptDecl {
    pub name: String,
    pub parent_concept: String,
    pub kind: SubConceptKind,
    pub span: Span,
}

/// Sub-concept can be either enum-like or record-like
#[derive(Debug, Clone, PartialEq)]
pub enum SubConceptKind {
    Enum { variants: Vec<String> },
    Record { fields: Vec<Field> },
}

/// Definition - compile-time pattern matching for concept variants
#[derive(Debug, Clone, PartialEq)]
pub struct DefinitionDecl {
    pub name: String,
    pub variants: Vec<VariantPattern>,
    pub span: Span,
}

/// A variant pattern with field conditions
#[derive(Debug, Clone, PartialEq)]
pub struct VariantPattern {
    pub name: String,
    pub conditions: Vec<FieldCondition>,
    pub span: Span,
}

/// A condition on a field within a variant pattern
#[derive(Debug, Clone, PartialEq)]
pub struct FieldCondition {
    pub field_name: String,
    pub condition: Condition,
    pub span: Span,
}

/// The type of condition for field matching
#[derive(Debug, Clone, PartialEq)]
pub enum Condition {
    Any,             // matches any value
    Is(Vec<String>), // matches specific values (e.g., "is Glass or is Plastic")
}

/// Expression AST for conditions and queries
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
    NumberLit(i64),
    DecimalLit(f64),
    TextLit(String),
    BooleanLit(bool),
    Identifier(Vec<String>),
    FieldAccess(Box<Expr>, String),
    Comparison(Box<Expr>, CompOp, Box<Expr>),
    Logical(Box<Expr>, LogicalOp, Box<Expr>),
    Unary(UnaryOp, Box<Expr>),
    Quantifier(QuantifierKind, String, Box<Expr>, Box<Expr>), /* forall/exists x in collection:
                                                               * predicate */
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CompOp {
    Eq, // ==
    Ne, // !=
    Lt, // <
    Le, // <=
    Gt, // >
    Ge, // >=
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LogicalOp {
    And,
    Or,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UnaryOp {
    Not,
    Neg,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum QuantifierKind {
    ForAll,
    Exists,
}

// ===== Parser Helper Types =====
// These enums are used internally by the LALRPOP parser to handle flexible
// ordering

/// Helper for parsing character/institution bodies with flexible ordering
#[derive(Debug, Clone, PartialEq)]
pub enum CharacterBodyItem {
    Field(Field),
    UsesBehaviors(Vec<BehaviorLink>),
    UsesSchedule(Vec<String>),
}

/// Helper for parsing institution bodies with flexible ordering
#[derive(Debug, Clone, PartialEq)]
pub enum InstitutionBodyItem {
    Field(Field),
    UsesBehaviors(Vec<BehaviorLink>),
    UsesSchedule(Vec<String>),
}

/// Helper for parsing template body items with flexible ordering
#[derive(Debug, Clone, PartialEq)]
pub enum TemplateBodyItem {
    Field(Field),
    Include(String),
    UsesBehaviors(Vec<BehaviorLink>),
    UsesSchedule(Vec<String>),
}

/// Helper for parsing behavior link fields
#[derive(Debug, Clone, PartialEq)]
pub enum BehaviorLinkField {
    Tree(Vec<String>),
    Condition(Expr),
    Priority(Priority),
}
