// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later

//! Module definition syntax element.

use crate::{rc::*, src_ref::*, syntax::*};

/// Module definition.
#[derive(Clone, Default)]
pub struct ModuleDefinition {
    /// Documentation.
    pub doc: Option<DocBlock>,
    /// Visibility of the module.
    pub visibility: Visibility,
    /// Name of the module.
    pub id: Identifier,
    /// Module body. ('None' if external module
    pub body: Option<Body>,
    /// Source code reference.
    pub src_ref: SrcRef,
}

impl ModuleDefinition {
    /// Create a new module definition.
    pub fn new(visibility: Visibility, id: Identifier) -> Rc<Self> {
        Rc::new(Self {
            visibility,
            id,
            ..Default::default()
        })
    }
}

impl SrcReferrer for ModuleDefinition {
    fn src_ref(&self) -> SrcRef {
        self.src_ref.clone()
    }
}

impl TreeDisplay for ModuleDefinition {
    fn tree_print(&self, f: &mut std::fmt::Formatter, mut depth: TreeState) -> std::fmt::Result {
        if let Some(body) = &self.body {
            writeln!(
                f,
                "{:depth$}ModuleDefinition {visibility}'{id}':",
                "",
                id = self.id,
                visibility = self.visibility,
            )?;
            depth.indent();
            if let Some(doc) = &self.doc {
                doc.tree_print(f, depth)?;
            }
            body.tree_print(f, depth)
        } else {
            writeln!(
                f,
                "{:depth$}ModuleDefinition {visibility}'{id}' (external)",
                "",
                id = self.id,
                visibility = self.visibility,
            )?;
            if let Some(doc) = &self.doc {
                doc.tree_print(f, depth)?;
            }
            Ok(())
        }
    }
}

impl std::fmt::Display for ModuleDefinition {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{visibility}mod {id}",
            id = self.id,
            visibility = self.visibility,
        )
    }
}

impl std::fmt::Debug for ModuleDefinition {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{visibility}mod {id:?}",
            id = self.id,
            visibility = self.visibility,
        )
    }
}

impl Doc for ModuleDefinition {
    fn doc(&self) -> Option<DocBlock> {
        self.doc.clone()
    }
}
