// src/ty.rs

#[derive(Debug, PartialEq, Clone)]
pub enum Ownership {
    Copy,
    Move,
    Share,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Effect {
    Total,
    Exn(Box<Type>),
    Alloc,
    Nondet,
    UserEffect(String),
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Variance {
    Covariant,
    Contravariant,
    Invariant,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Type {
    Int,
    Float,
    Bool,
    Char,
    String,
    Unit,
    Never,
    Named(String),
    Generic { name: String, args: Vec<Type> },
    Tuple(Vec<Type>),
    Reference { is_mut: bool, inner: Box<Type> },
    Function { params: Vec<Type>, effects: Vec<Effect>, ret: Box<Type> },
    Shared { inner: Box<Type>, region: Option<String> },
    Unknown,
}

impl Type {
    pub fn ownership(&self) -> Ownership {
        match self {
            Type::Int | Type::Float | Type::Bool | Type::Char | Type::Unit | Type::Never => {
                Ownership::Copy
            }
            Type::String => Ownership::Move,
            Type::Reference { .. } => Ownership::Copy,
            Type::Tuple(tys) => {
                if tys.iter().all(|t| t.ownership() == Ownership::Copy) {
                    Ownership::Copy
                } else {
                    Ownership::Move
                }
            }
            Type::Generic { name, args } => {
                if name == "Shared" {
                    Ownership::Share
                } else if args.iter().all(|t| t.ownership() == Ownership::Copy) {
                    Ownership::Copy
                } else {
                    Ownership::Move
                }
            }
            Type::Shared { .. } => Ownership::Share,
            Type::Function { .. } => Ownership::Copy,
            Type::Named(name) if name == "Share" => Ownership::Copy,
            Type::Named(_) => Ownership::Move,
            // Conservative: treat Unknown as Copy to avoid spurious moves before inference.
            Type::Unknown => Ownership::Copy,
        }
    }
}
