use crate::syntax::ast::*;
use crate::syntax::lexer::Token;

grammar;

// ===== Top-level =====

pub File: File = {
    <declarations:Declaration*> => File { declarations }
};

Declaration: Declaration = {
    <u:UseDecl> => Declaration::Use(u),
    <c:Character> => Declaration::Character(c),
    <t:Template> => Declaration::Template(t),
    <l:LifeArc> => Declaration::LifeArc(l),
    <s:Schedule> => Declaration::Schedule(s),
    <b:Behavior> => Declaration::Behavior(b),
    <i:Institution> => Declaration::Institution(i),
    <r:Relationship> => Declaration::Relationship(r),
    <loc:Location> => Declaration::Location(loc),
    <sp:Species> => Declaration::Species(sp),
    <concept:ConceptDecl> => Declaration::Concept(concept),
    <sub:SubConceptDecl> => Declaration::SubConcept(sub),
    <comp:ConceptComparisonDecl> => Declaration::ConceptComparison(comp),
};

// ===== Use declarations =====

UseDecl: UseDecl = {
    "use" <path:Path> ";" => UseDecl {
        path,
        kind: UseKind::Single,
        span: Span::new(0, 0),  // TODO: track actual spans
    },
    "use" <base:PathSegments> "::" "{" <items:Comma<Ident>> "}" ";" => UseDecl {
        path: base,
        kind: UseKind::Grouped(items),
        span: Span::new(0, 0),
    },
    "use" <path:PathSegments> "::" "*" ";" => UseDecl {
        path,
        kind: UseKind::Wildcard,
        span: Span::new(0, 0),
    },
};

Path: Vec<String> = {
    <PathSegments>
};

PathSegments: Vec<String> = {
    <Ident> => vec![<>],
    <mut v:PathSegments> "::" <i:Ident> => {
        v.push(i);
        v
    }
};

DottedPath: Vec<String> = {
    <Ident> => vec![<>],
    <mut v:DottedPath> "." <i:Ident> => {
        v.push(i);
        v
    }
};

// ===== Character =====

Character: Character = {
    "character" <name:Ident> <species:(":" <Ident>)?> <template:TemplateClause?> "{" <body:CharacterBody> "}" => {
        Character {
            name,
            species,
            fields: body.0,
            template,
            uses_behaviors: body.1,
            uses_schedule: body.2,
            span: Span::new(0, 0),
        }
    }
};

// Character body can contain fields and uses clauses in any order
CharacterBody: (Vec<Field>, Option<Vec<BehaviorLink>>, Option<Vec<String>>) = {
    <items:CharacterBodyItem*> => {
        let mut fields = Vec::new();
        let mut uses_behaviors = None;
        let mut uses_schedule = None;
        
        for item in items {
            match item {
                CharacterBodyItem::Field(f) => fields.push(f),
                CharacterBodyItem::UsesBehaviors(b) => uses_behaviors = Some(b),
                CharacterBodyItem::UsesSchedule(s) => uses_schedule = Some(s),
            }
        }
        
        (fields, uses_behaviors, uses_schedule)
    }
};

CharacterBodyItem: CharacterBodyItem = {
    <Field> => CharacterBodyItem::Field(<>),
    <UsesBehaviorsClause> => CharacterBodyItem::UsesBehaviors(<>),
    <UsesScheduleClause> => CharacterBodyItem::UsesSchedule(<>),
};

TemplateClause: Vec<String> = {
    "from" <t:Ident> <rest:("," <Ident>)*> => {
        let mut templates = vec![t];
        templates.extend(rest);
        templates
    }
};

// uses behaviors: [...]
UsesBehaviorsClause: Vec<BehaviorLink> = {
    "uses" "behaviors" ":" "[" <links:Comma<BehaviorLinkItem>> "]" => links,
};

// Individual behavior link: { tree: BehaviorName, priority: high, when: condition }
BehaviorLinkItem: BehaviorLink = {
    "{" <fields:BehaviorLinkField+> "}" => {
        let mut tree = None;
        let mut condition = None;
        let mut priority = Priority::Normal;
        
        for field in fields {
            match field {
                BehaviorLinkField::Tree(t) => tree = Some(t),
                BehaviorLinkField::Condition(c) => condition = Some(c),
                BehaviorLinkField::Priority(p) => priority = p,
            }
        }
        
        BehaviorLink {
            tree: tree.expect("behavior link must have 'tree' field"),
            condition,
            priority,
            span: Span::new(0, 0),
        }
    }
};

// Fields within a behavior link
BehaviorLinkField: BehaviorLinkField = {
    "tree" ":" <path:Path> ","? => BehaviorLinkField::Tree(path),
    "when" ":" <expr:Expr> ","? => BehaviorLinkField::Condition(expr),
    "priority" ":" <p:PriorityLevel> ","? => BehaviorLinkField::Priority(p),
};

PriorityLevel: Priority = {
    <s:Ident> => match s.as_str() {
        "low" => Priority::Low,
        "normal" => Priority::Normal,
        "high" => Priority::High,
        "critical" => Priority::Critical,
        _ => Priority::Normal, // Default to normal for invalid values
    },
};

// uses schedule: ScheduleName or uses schedules: [Name1, Name2]
UsesScheduleClause: Vec<String> = {
    "uses" "schedule" ":" <name:Ident> => vec![name],
    "uses" "schedules" ":" "[" <names:Comma<Ident>> "]" => names,
};

// ===== Template =====

Template: Template = {
    "template" <name:Ident> <species_base:(":" <Ident>)?> <strict:"strict"?> "{" <body:TemplateBodyItem*> "}" => {
        let mut fields = Vec::new();
        let mut includes = Vec::new();
        let mut uses_behaviors = None;
        let mut uses_schedule = None;

        for item in body {
            match item {
                TemplateBodyItem::Field(f) => fields.push(f),
                TemplateBodyItem::Include(inc) => includes.push(inc),
                TemplateBodyItem::UsesBehaviors(b) => uses_behaviors = Some(b),
                TemplateBodyItem::UsesSchedule(s) => uses_schedule = Some(s),
            }
        }

        Template {
            name,
            species_base,
            fields,
            strict: strict.is_some(),
            includes,
            uses_behaviors,
            uses_schedule,
            span: Span::new(0, 0),
        }
    }
};

// Template body items (fields, includes, uses behaviors, uses schedule)
TemplateBodyItem: TemplateBodyItem = {
    <Field> => TemplateBodyItem::Field(<>),
    "include" <name:Ident> => TemplateBodyItem::Include(name),
    <TemplateUsesBehaviorsClause> => TemplateBodyItem::UsesBehaviors(<>),
    <TemplateUsesScheduleClause> => TemplateBodyItem::UsesSchedule(<>),
};

// Template-level behavior links (simple list, no priorities/conditions)
TemplateUsesBehaviorsClause: Vec<BehaviorLink> = {
    "uses" "behaviors" ":" <first:Ident> <rest:("," <Ident>)*> => {
        let mut names = vec![first];
        names.extend(rest);
        names.into_iter().map(|name| BehaviorLink {
            tree: vec![name],
            condition: None,
            priority: Priority::Normal,
            span: Span::new(0, 0),
        }).collect()
    },
};

// Template-level schedule links
TemplateUsesScheduleClause: Vec<String> = {
    "uses" "schedule" ":" <name:Ident> => vec![name],
};

// Template/Species include clause
Include: String = {
    "include" <name:Ident> => name
};

// ===== Fields =====

Field: Field = {
    <path:DottedPath> ":" <value:Value> => Field {
        name: path.join("."),
        value,
        span: Span::new(0, 0),
    },
    <pb:ProseBlock> => Field {
        name: pb.tag.clone(),
        value: Value::ProseBlock(pb),
        span: Span::new(0, 0),
    }
};

Value: Value = {
    <NumberLit> => Value::Number(<>),
    <DecimalLit> => Value::Decimal(<>),
    <TextLit> => Value::Text(<>),
    <BoolLit> => Value::Boolean(<>),
    "any" => Value::Any,
    <lo:NumberLit> ".." <hi:NumberLit> => Value::Range(
        Box::new(Value::Number(lo)),
        Box::new(Value::Number(hi))
    ),
    <lo:DecimalLit> ".." <hi:DecimalLit> => Value::Range(
        Box::new(Value::Decimal(lo)),
        Box::new(Value::Decimal(hi))
    ),
    <t:Time> => Value::Time(t),
    <d:Duration> => Value::Duration(d),
    <p:Path> => Value::Identifier(p),
    <ProseBlock> => Value::ProseBlock(<>),
    "[" <values:Comma<Value>> "]" => Value::List(values),
    "{" <fields:Field*> "}" => Value::Object(fields),
    <Override> => Value::Override(<>),
};

BoolLit: bool = {
    "true" => true,
    "false" => false,
};

Time: Time = {
    <s:TimeLit> => {
        let parts: Vec<&str> = s.split(':').collect();
        let hour = parts[0].parse().unwrap_or(0);
        let minute = parts[1].parse().unwrap_or(0);
        let second = if parts.len() > 2 {
            parts[2].parse().unwrap_or(0)
        } else {
            0
        };
        Time { hour, minute, second }
    }
};

Duration: Duration = {
    <s:DurationLit> => {
        let mut hours = 0;
        let mut minutes = 0;
        let mut seconds = 0;

        let mut num = String::new();
        for ch in s.chars() {
            if ch.is_ascii_digit() {
                num.push(ch);
            } else {
                let val: u32 = num.parse().unwrap_or(0);
                match ch {
                    'h' => hours = val,
                    'm' => minutes = val,
                    's' => seconds = val,
                    _ => {}
                }
                num.clear();
            }
        }

        Duration { hours, minutes, seconds }
    }
};

// Duration string for decorator timeouts/cooldowns (e.g., "5s", "30m", "2h", "1d")
BehaviorDurationLit: String = {
    <s:DurationLit> => s
};

ProseBlock: ProseBlock = {
    ProseBlockToken
};

Override: Override = {
    "@" <base:Path> "{" <overrides:OverrideOp*> "}" => Override {
        base,
        overrides,
        span: Span::new(0, 0),
    }
};

OverrideOp: OverrideOp = {
    "remove" <name:Ident> => OverrideOp::Remove(name),
    "append" <f:Field> => OverrideOp::Append(f),
    <f:Field> => OverrideOp::Set(f),
};

// ===== Life Arc =====

LifeArc: LifeArc = {
    "life_arc" <name:Ident> <reqs:RequiresClause?> "{" <fields:Field*> <states:ArcState*> "}" => LifeArc {
        name,
        required_fields: reqs.unwrap_or_default(),
        states,
        span: Span::new(0, 0),
    }
};

RequiresClause: Vec<FieldRequirement> = {
    "requires" "{" <reqs:Comma<FieldReq>> "}" => reqs,
};

FieldReq: FieldRequirement = {
    <name:Ident> ":" <type_name:Ident> => FieldRequirement {
        name,
        type_name,
        span: Span::new(0, 0),
    }
};

ArcState: ArcState = {
    "state" <name:Ident> "{" <on_enter:OnEnter?> <fields:Field*> <transitions:Transition*> "}" => ArcState {
        name,
        on_enter,
        transitions,
        span: Span::new(0, 0),
    }
};

OnEnter: Vec<Field> = {
    "on" "enter" "{" <fields:Field*> "}" => fields
};

Transition: Transition = {
    "on" <cond:Expr> "->" <to:Ident> => Transition {
        to,
        condition: cond,
        span: Span::new(0, 0),
    }
};

// ===== Schedule =====

Schedule: Schedule = {
    // Simple schedule: schedule Name { ... }
    "schedule" <name:Ident> "{" <body:ScheduleBody> "}" => Schedule {
        name,
        extends: None,
        fields: body.0,
        blocks: body.1,
        recurrences: body.2,
        span: Span::new(0, 0),
    },
    // Extending schedule: schedule Name extends Base { ... }
    "schedule" <name:Ident> "extends" <base:Ident> "{" <body:ScheduleBody> "}" => Schedule {
        name,
        extends: Some(base),
        fields: body.0,
        blocks: body.1,
        recurrences: body.2,
        span: Span::new(0, 0),
    }
};

// Schedule body can contain fields (prose blocks), blocks, and recurrence patterns
ScheduleBody: (Vec<Field>, Vec<ScheduleBlock>, Vec<RecurrencePattern>) = {
    <items:ScheduleBodyItem*> => {
        let mut fields = Vec::new();
        let mut blocks = Vec::new();
        let mut recurrences = Vec::new();
        
        for item in items {
            match item {
                ScheduleBodyItem::Field(f) => fields.push(f),
                ScheduleBodyItem::Block(b) => blocks.push(b),
                ScheduleBodyItem::Recurrence(r) => recurrences.push(r),
            }
        }
        
        (fields, blocks, recurrences)
    }
};

ScheduleBodyItem: ScheduleBodyItem = {
    <Field> => ScheduleBodyItem::Field(<>),
    <ScheduleBlock> => ScheduleBodyItem::Block(<>),
    <RecurrencePattern> => ScheduleBodyItem::Recurrence(<>),
};

ScheduleBlock: ScheduleBlock = {
    // Legacy syntax: time -> time : activity { fields }
    <start:Time> "->" <end:Time> ":" <activity:Ident> "{" <fields:Field*> "}" => ScheduleBlock {
        name: None,
        is_override: false,
        start,
        end,
        activity,
        action: None,
        temporal_constraint: None,
        fields,
        span: Span::new(0, 0),
    },
    
    // Named block: block name { time, action, fields }
    "block" <name:Ident> "{" <content:BlockContent> "}" => ScheduleBlock {
        name: Some(name),
        is_override: false,
        start: content.0,
        end: content.1,
        activity: String::new(), // Empty for new syntax
        action: content.2,
        temporal_constraint: None,
        fields: content.3,
        span: Span::new(0, 0),
    },
    
    // Override block: override name { time, action, fields }
    "override" <name:Ident> "{" <content:BlockContent> "}" => ScheduleBlock {
        name: Some(name),
        is_override: true,
        start: content.0,
        end: content.1,
        activity: String::new(), // Empty for new syntax
        action: content.2,
        temporal_constraint: None,
        fields: content.3,
        span: Span::new(0, 0),
    }
};

// Block content: time range, optional action, and fields
BlockContent: (Time, Time, Option<Vec<String>>, Vec<Field>) = {
    <items:BlockContentItem+> => {
        let mut start = None;
        let mut end = None;
        let mut action = None;
        let mut fields = Vec::new();
        
        for item in items {
            match item {
                BlockContentItem::TimeRange(s, e) => {
                    start = Some(s);
                    end = Some(e);
                }
                BlockContentItem::Field(f) => {
                    if f.name == "action" {
                        // Extract action as qualified path from identifier value
                        if let Value::Identifier(path) = &f.value {
                            action = Some(path.clone());
                        }
                    } else {
                        fields.push(f);
                    }
                }
            }
        }
        
        (
            start.expect("block must have time range"),
            end.expect("block must have time range"),
            action,
            fields
        )
    }
};

BlockContentItem: BlockContentItem = {
    <start:Time> "->" <end:Time> ","? => BlockContentItem::TimeRange(start, end),
    <Field> => BlockContentItem::Field(<>),
};

// Recurrence pattern: recurrence Name on DayOfWeek { blocks }
RecurrencePattern: RecurrencePattern = {
    "recurrence" <name:Ident> "on" <day:Ident> "{" <blocks:ScheduleBlock+> "}" => RecurrencePattern {
        name,
        constraint: TemporalConstraint::DayOfWeek(day),
        blocks,
        span: Span::new(0, 0),
    }
};

// ===== Behavior Trees =====

Behavior: Behavior = {
    "behavior" <name:Ident> "{" <fields:Field*> <root:BehaviorNode> "}" => Behavior {
        name,
        root,
        span: Span::new(0, 0),
    }
};

BehaviorNode: BehaviorNode = {
    <SelectorNode>,
    <SequenceNode>,
    <ConditionNode>,
    <DecoratorNode>,
    <ActionNode>,
    <SubTreeNode>,
};

// Selector node: choose { ... } or choose label { ... }
SelectorNode: BehaviorNode = {
    "choose" <label:Ident?> "{" <children:BehaviorNode+> "}" => BehaviorNode::Selector {
        label,
        children,
    },
};

// Sequence node: then { ... } or then label { ... }
SequenceNode: BehaviorNode = {
    "then" <label:Ident?> "{" <children:BehaviorNode+> "}" => BehaviorNode::Sequence {
        label,
        children,
    },
};

// Condition node: if(expr) or when(expr)
// if(expr) { child } is the decorator form (replaces old "guard" keyword)
ConditionNode: BehaviorNode = {
    "if" "(" <condition:Expr> ")" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::If(condition),
        child: Box::new(child),
    },
    "if" "(" <condition:Expr> ")" => BehaviorNode::Condition(condition),
    "when" "(" <condition:Expr> ")" => BehaviorNode::Condition(condition),
};

// Decorator node: keyword [params] { child }
DecoratorNode: BehaviorNode = {
    <DecoratorRepeat>,
    <DecoratorRepeatN>,
    <DecoratorRepeatRange>,
    <DecoratorInvert>,
    <DecoratorRetry>,
    <DecoratorTimeout>,
    <DecoratorCooldown>,
    <DecoratorSucceedAlways>,
    <DecoratorFailAlways>,
};

DecoratorRepeat: BehaviorNode = {
    "repeat" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::Repeat,
        child: Box::new(child),
    },
};

DecoratorRepeatN: BehaviorNode = {
    "repeat" "(" <n:NumberLit> ")" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::RepeatN(n as u32),
        child: Box::new(child),
    },
};

DecoratorRepeatRange: BehaviorNode = {
    "repeat" "(" <min:NumberLit> ".." <max:NumberLit> ")" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::RepeatRange(min as u32, max as u32),
        child: Box::new(child),
    },
};

DecoratorInvert: BehaviorNode = {
    "invert" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::Invert,
        child: Box::new(child),
    },
};

DecoratorRetry: BehaviorNode = {
    "retry" "(" <n:NumberLit> ")" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::Retry(n as u32),
        child: Box::new(child),
    },
};

DecoratorTimeout: BehaviorNode = {
    "timeout" "(" <duration:BehaviorDurationLit> ")" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::Timeout(duration),
        child: Box::new(child),
    },
};

DecoratorCooldown: BehaviorNode = {
    "cooldown" "(" <duration:BehaviorDurationLit> ")" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::Cooldown(duration),
        child: Box::new(child),
    },
};

DecoratorSucceedAlways: BehaviorNode = {
    "succeed_always" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::SucceedAlways,
        child: Box::new(child),
    },
};

DecoratorFailAlways: BehaviorNode = {
    "fail_always" "{" <child:BehaviorNode> "}" => BehaviorNode::Decorator {
        decorator_type: DecoratorType::FailAlways,
        child: Box::new(child),
    },
};

// Action node: action_name or action_name(params)
ActionNode: BehaviorNode = {
    <name:Ident> "(" <params:Comma<ActionParam>> ")" => BehaviorNode::Action(name, params),
    <name:Ident> => BehaviorNode::Action(name, vec![]),
};

ActionParam: Field = {
    // Named parameter: field: value
    <path:DottedPath> ":" <value:Value> => Field {
        name: path.join("."),
        value,
        span: Span::new(0, 0),
    },
    // Positional parameter: just a value (use empty string as field name)
    <value:Value> => Field {
        name: String::new(),
        value,
        span: Span::new(0, 0),
    },
};

// Subtree node: include path::to::subtree
SubTreeNode: BehaviorNode = {
    "include" <path:Path> => BehaviorNode::SubTree(path),
};

// ===== Institution =====

Institution: Institution = {
    "institution" <name:Ident> "{" <body:InstitutionBody> "}" => {
        Institution {
            name,
            fields: body.0,
            uses_behaviors: body.1,
            uses_schedule: body.2,
            span: Span::new(0, 0),
        }
    }
};

// Institution body can contain fields and uses clauses in any order
InstitutionBody: (Vec<Field>, Option<Vec<BehaviorLink>>, Option<Vec<String>>) = {
    <items:InstitutionBodyItem*> => {
        let mut fields = Vec::new();
        let mut uses_behaviors = None;
        let mut uses_schedule = None;
        
        for item in items {
            match item {
                InstitutionBodyItem::Field(f) => fields.push(f),
                InstitutionBodyItem::UsesBehaviors(b) => uses_behaviors = Some(b),
                InstitutionBodyItem::UsesSchedule(s) => uses_schedule = Some(s),
            }
        }
        
        (fields, uses_behaviors, uses_schedule)
    }
};

InstitutionBodyItem: InstitutionBodyItem = {
    <Field> => InstitutionBodyItem::Field(<>),
    <UsesBehaviorsClause> => InstitutionBodyItem::UsesBehaviors(<>),
    <UsesScheduleClause> => InstitutionBodyItem::UsesSchedule(<>),
};

// ===== Relationship =====

Relationship: Relationship = {
    "relationship" <name:Ident> "{" <participants:Participant+> <fields:Field*> "}" => Relationship {
        name,
        participants,
        fields,
        span: Span::new(0, 0),
    }
};

Participant: Participant = {
    // Participant with role and block (block required)
    <name:Path> "as" <role:Ident> "{" <fields:Field*> "}" => Participant {
        name,
        role: Some(role),
        fields,
        span: Span::new(0, 0),
    },
    // Participant without role (block still required)
    <name:Path> "{" <fields:Field*> "}" => Participant {
        name,
        role: None,
        fields,
        span: Span::new(0, 0),
    },
};

// ===== Location =====

Location: Location = {
    "location" <name:Ident> "{" <fields:Field*> "}" => Location {
        name,
        fields,
        span: Span::new(0, 0),
    }
};

// ===== Species =====

Species: Species = {
    "species" <name:Ident> "{" <includes:Include*> <fields:Field*> "}" => Species {
        name,
        includes,
        fields,
        span: Span::new(0, 0),
    }
};

// ===== Enum =====

// ===== Type System Declarations =====

ConceptDecl: ConceptDecl = {
    "concept" <name:Ident> => ConceptDecl {
        name,
        span: Span::new(0, 0),
    }
};

SubConceptDecl: SubConceptDecl = {
    // Enum-like sub_concept: sub_concept Cup.Type { Small, Medium, Large }
    "sub_concept" <parent:Ident> "." <name:Ident> "{" <variants:Comma<Ident>> "}" => {
        SubConceptDecl {
            name,
            parent_concept: parent,
            kind: SubConceptKind::Enum { variants },
            span: Span::new(0, 0),
        }
    },
    // Record-like sub_concept with at least one field: sub_concept Cup.Material { weight: 100 }
    "sub_concept" <parent:Ident> "." <name:Ident> "{" <first:Ident> ":" <first_val:Value> <rest:("," <Ident> ":" <Value>)*> ","? "}" => {
        let mut fields = vec![Field {
            name: first,
            value: first_val,
            span: Span::new(0, 0),
        }];

        for (field_name, field_val) in rest {
            fields.push(Field {
                name: field_name,
                value: field_val,
                span: Span::new(0, 0),
            });
        }

        SubConceptDecl {
            name,
            parent_concept: parent,
            kind: SubConceptKind::Record { fields },
            span: Span::new(0, 0),
        }
    },
};

ConceptComparisonDecl: ConceptComparisonDecl = {
    "concept_comparison" <name:Ident> "{" <variants:Comma<VariantPattern>> "}" => ConceptComparisonDecl {
        name,
        variants,
        span: Span::new(0, 0),
    }
};

VariantPattern: VariantPattern = {
    <name:Ident> ":" "{" <conditions:Comma<FieldCondition>> "}" => VariantPattern {
        name,
        conditions,
        span: Span::new(0, 0),
    }
};

FieldCondition: FieldCondition = {
    <field:Ident> ":" "any" => FieldCondition {
        field_name: field,
        condition: Condition::Any,
        span: Span::new(0, 0),
    },
    <field:Ident> ":" <cond:IsCondition> => FieldCondition {
        field_name: field,
        condition: Condition::Is(cond),
        span: Span::new(0, 0),
    },
};

// Parse "FieldName is Value1 or FieldName is Value2" and extract the values
IsCondition: Vec<String> = {
    <first:IsValue> <rest:("or" <IsValue>)*> => {
        let mut values = vec![first];
        values.extend(rest);
        values
    }
};

IsValue: String = {
    <field:Ident> "is" <value:Ident> => value
};

// ===== Expressions =====
// Expression grammar with proper precedence:
// or > and > not > field_access > comparison > term

Expr: Expr = {
    <OrExpr>,
};

// Logical OR (lowest precedence)
OrExpr: Expr = {
    <left:OrExpr> "or" <right:AndExpr> => {
        Expr::Logical(
            Box::new(left),
            LogicalOp::Or,
            Box::new(right)
        )
    },
    <AndExpr>,
};

// Logical AND
AndExpr: Expr = {
    <left:AndExpr> "and" <right:NotExpr> => {
        Expr::Logical(
            Box::new(left),
            LogicalOp::And,
            Box::new(right)
        )
    },
    <NotExpr>,
};

// Unary NOT
NotExpr: Expr = {
    "not" <expr:NotExpr> => {
        Expr::Unary(
            UnaryOp::Not,
            Box::new(expr)
        )
    },
    <ComparisonExpr>,
};

// Comparison expressions
ComparisonExpr: Expr = {
    // Equality: field access or path is (literal or identifier)
    <left:FieldAccessExpr> "is" <right:FieldAccessExpr> => {
        Expr::Comparison(
            Box::new(left),
            CompOp::Eq,
            Box::new(right)
        )
    },
    // Comparison: field access or path > literal/identifier, etc.
    <left:FieldAccessExpr> <op:InequalityOp> <right:FieldAccessExpr> => {
        Expr::Comparison(
            Box::new(left),
            op,
            Box::new(right)
        )
    },
    // Just a field access expression
    <FieldAccessExpr>,
};

// Field access with dot notation (binds tightest)
FieldAccessExpr: Expr = {
    <base:FieldAccessExpr> "." <field:Ident> => {
        Expr::FieldAccess(
            Box::new(base),
            field
        )
    },
    <PrimaryExpr>,
};

// Primary expressions (atoms)
PrimaryExpr: Expr = {
    "self" => Expr::Identifier(vec!["self".to_string()]),
    "other" => Expr::Identifier(vec!["other".to_string()]),
    <Literal>,
    <Path> => Expr::Identifier(<>),
};

InequalityOp: CompOp = {
    ">" => CompOp::Gt,
    ">=" => CompOp::Ge,
    "<" => CompOp::Lt,
    "<=" => CompOp::Le,
};

Literal: Expr = {
    <NumberLit> => Expr::NumberLit(<>),
    <DecimalLit> => Expr::DecimalLit(<>),
    <TextLit> => Expr::TextLit(<>),
    <BoolLit> => Expr::BooleanLit(<>),
};

// ===== Helpers =====

Comma<T>: Vec<T> = {
    <v:(<T> ",")*> <e:T?> => match e {
        None => v,
        Some(e) => {
            let mut v = v;
            v.push(e);
            v
        }
    }
};

// ===== Token conversion =====

extern {
    type Location = usize;
    type Error = crate::syntax::ParseError;

    enum Token {
        // Keywords
        "use" => Token::Use,
        "character" => Token::Character,
        "template" => Token::Template,
        "life_arc" => Token::LifeArc,
        "schedule" => Token::Schedule,
        "behavior" => Token::Behavior,
        "institution" => Token::Institution,
        "relationship" => Token::Relationship,
        "location" => Token::Location,
        "species" => Token::Species,
        "concept" => Token::Concept,
        "sub_concept" => Token::SubConcept,
        "concept_comparison" => Token::ConceptComparison,
        "any" => Token::Any,
        "requires" => Token::Requires,
        "state" => Token::State,
        "on" => Token::On,
        "enter" => Token::Enter,
        "as" => Token::As,
        "self" => Token::SelfKw,
        "other" => Token::Other,
        "remove" => Token::Remove,
        "append" => Token::Append,
        "forall" => Token::ForAll,
        "exists" => Token::Exists,
        "in" => Token::In,
        "where" => Token::Where,
        "and" => Token::And,
        "or" => Token::Or,
        "not" => Token::Not,
        "strict" => Token::Strict,
        "include" => Token::Include,
        "from" => Token::From,
        "is" => Token::Is,
        "uses" => Token::Uses,
        "behaviors" => Token::Behaviors,
        "schedules" => Token::Schedules,
        "tree" => Token::Tree,
        "priority" => Token::Priority,
        "extends" => Token::Extends,
        "override" => Token::Override,
        "recurrence" => Token::Recurrence,
        "season" => Token::Season,
        "block" => Token::Block,
        "true" => Token::True,
        "false" => Token::False,

        // Behavior tree keywords
        "choose" => Token::Choose,
        "then" => Token::Then,
        "if" => Token::If,
        "when" => Token::When,
        "repeat" => Token::Repeat,
        "invert" => Token::Invert,
        "retry" => Token::Retry,
        "timeout" => Token::Timeout,
        "cooldown" => Token::Cooldown,
        "succeed_always" => Token::SucceedAlways,
        "fail_always" => Token::FailAlways,

        // Literals
        Ident => Token::Ident(<String>),
        NumberLit => Token::NumberLit(<i64>),
        DecimalLit => Token::DecimalLit(<f64>),
        TextLit => Token::TextLit(<String>),
        TimeLit => Token::TimeLit(<String>),
        DurationLit => Token::DurationLit(<String>),
        ProseBlockToken => Token::ProseBlock(<ProseBlock>),

        // Punctuation
        "{" => Token::LBrace,
        "}" => Token::RBrace,
        "(" => Token::LParen,
        ")" => Token::RParen,
        "[" => Token::LBracket,
        "]" => Token::RBracket,
        ":" => Token::Colon,
        "::" => Token::ColonColon,
        ";" => Token::Semicolon,
        "," => Token::Comma,
        "." => Token::Dot,
        ".." => Token::DotDot,
        "*" => Token::Star,
        "?" => Token::Question,
        "@" => Token::At,

        // Operators
        ">" => Token::Gt,
        ">=" => Token::Ge,
        "<" => Token::Lt,
        "<=" => Token::Le,
        "->" => Token::Arrow,
    }
}
