use std::borrow::Cow;

use chumsky::prelude::Spanned;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Ident<'src>(pub Cow<'src, str>);

#[derive(Debug, Clone, PartialEq)]
pub enum Token<'src> {
    Ident(Ident<'src>),

    Bool(bool),
    Integer(i64),
    Decimal(f64),
    String(Cow<'src, str>),
    Regex(Cow<'src, str>),

    Add,
    Sub,
    Mul,
    Div,
    Mod,

    Equal,
    NotEqual,
    GreaterThan,
    LessThan,
    GreaterEqual,
    LessEqual,

    Not,

    And,
    Or,

    ParenOpen,
    ParenClose,
    BracketOpen,
    BracketClose,

    Comma,
    Period,
}

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum BinOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,

    Equal,
    NotEqual,
    GreaterThan,
    LessThan,
    GreaterEqual,
    LessEqual,

    And,
    Or,
}

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum UnOp {
    Not,

    Plus,
    Neg,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Expr<'src> {
    Ident(Ident<'src>),

    Bool(bool),
    Integer(i64),
    Decimal(f64),
    String(Cow<'src, str>),
    Regex(Cow<'src, str>),

    Function(Box<Spanned<Self>>, Spanned<Vec<Spanned<Self>>>),
    Method(
        Box<Spanned<Self>>,
        Spanned<Ident<'src>>,
        Spanned<Vec<Spanned<Self>>>,
    ),

    Member(Box<Spanned<Self>>, Spanned<Ident<'src>>),
    Index(Box<Spanned<Self>>, Box<Spanned<Self>>),

    BinOp(Spanned<BinOp>, Box<Spanned<Self>>, Box<Spanned<Self>>),
    UnOp(Spanned<UnOp>, Box<Spanned<Self>>),

    Group(Box<Spanned<Self>>),
}
