use super::*;

impl Parser {
    pub(super) fn parse_module(&mut self) -> Result<Module, ParseError> {
        let line = self.current().line;
        self.expect_exact(&TokenKind::Module)?;
        let name_tok =
            self.expect_kind(&TokenKind::Ident(String::new()), "Expected module name")?;
        let name = match name_tok.kind {
            TokenKind::Ident(s) => s,
            _ => unreachable!(),
        };
        self.skip_newlines();

        let mut depends = Vec::new();
        let mut exposes = Vec::new();
        let mut exposes_opaque = Vec::new();
        let mut exposes_line = None;
        let mut intent = String::new();

        if self.is_indent() {
            self.advance(); // consume INDENT
            self.skip_newlines();

            while !self.is_dedent() && !self.is_eof() {
                match &self.current().kind {
                    TokenKind::Intent => {
                        intent = self.parse_module_intent()?;
                    }
                    TokenKind::Exposes => {
                        exposes_line = Some(self.current().line);
                        self.advance(); // consume 'exposes'
                        if matches!(self.current().kind, TokenKind::Ident(ref s) if s == "opaque") {
                            self.advance(); // consume 'opaque'
                            exposes_opaque = self.parse_bracket_ident_list()?;
                        } else {
                            exposes = self.parse_bracket_ident_list()?;
                        }
                    }
                    TokenKind::Depends => {
                        depends = self.parse_depends()?;
                    }
                    _ => break,
                }
                self.skip_newlines();
            }

            if self.is_dedent() {
                self.advance();
            }
        }

        Ok(Module {
            name,
            line,
            depends,
            exposes,
            exposes_opaque,
            exposes_line,
            intent,
        })
    }

    pub(super) fn parse_module_intent(&mut self) -> Result<String, ParseError> {
        self.expect_exact(&TokenKind::Intent)?;
        self.expect_exact(&TokenKind::Assign)?;
        let text = self.parse_inline_or_block_text()?;
        if text.is_empty() {
            return Err(self.error("Expected string or indented text after 'intent ='".to_string()));
        }
        Ok(text)
    }

    pub(super) fn parse_bracket_ident_list(&mut self) -> Result<Vec<String>, ParseError> {
        self.expect_exact(&TokenKind::LBracket)?;
        let mut items = Vec::new();

        while !self.check_exact(&TokenKind::RBracket) && !self.is_eof() {
            match self.current().kind.clone() {
                TokenKind::Ident(s) => {
                    items.push(s);
                    self.advance();
                }
                TokenKind::Comma => {
                    self.advance();
                }
                _ => break,
            }
        }

        self.expect_exact(&TokenKind::RBracket)?;
        self.skip_newlines();
        Ok(items)
    }

    pub(super) fn parse_depends(&mut self) -> Result<Vec<String>, ParseError> {
        self.expect_exact(&TokenKind::Depends)?;
        self.expect_exact(&TokenKind::LBracket)?;
        let mut items = Vec::new();

        while !self.check_exact(&TokenKind::RBracket) && !self.is_eof() {
            if self.check_exact(&TokenKind::Comma) {
                self.advance();
                continue;
            }
            items.push(self.parse_qualified_ident()?);
            if self.check_exact(&TokenKind::Comma) {
                self.advance();
            }
        }

        self.expect_exact(&TokenKind::RBracket)?;
        self.skip_newlines();
        Ok(items)
    }

    pub(super) fn parse_qualified_ident(&mut self) -> Result<String, ParseError> {
        let first = match self.current().kind.clone() {
            TokenKind::Ident(s) => {
                self.advance();
                s
            }
            _ => {
                return Err(self.error(format!(
                    "Expected identifier, found {}",
                    self.current().kind
                )));
            }
        };
        let mut parts = vec![first];

        while self.check_exact(&TokenKind::Dot) {
            self.advance(); // '.'
            match self.current().kind.clone() {
                TokenKind::Ident(s) => {
                    parts.push(s);
                    self.advance();
                }
                _ => {
                    return Err(self.error(format!(
                        "Expected identifier after '.', found {}",
                        self.current().kind
                    )));
                }
            }
        }

        Ok(parts.join("."))
    }
}
