//! This is in essence an (improved) duplicate of `rustc_ast/attr/mod.rs`.
//! That module is intended to be deleted in its entirety.
//!
//! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs`

use std::borrow::Cow;
use std::fmt::{Debug, Display};

use rustc_ast::token::{self, Delimiter, MetaVarKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
use rustc_ast_pretty::pprust;
use rustc_errors::{Diag, PResult};
use rustc_hir::{self as hir, AttrPath};
use rustc_parse::exp;
use rustc_parse::parser::{Parser, PathStyle, token_descr};
use rustc_session::errors::{create_lit_error, report_lit_error};
use rustc_session::parse::ParseSess;
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
use thin_vec::ThinVec;

use crate::ShouldEmit;
use crate::session_diagnostics::{
    InvalidMetaItem, InvalidMetaItemQuoteIdentSugg, InvalidMetaItemRemoveNegSugg, MetaBadDelim,
    MetaBadDelimSugg, SuffixedLiteralInAttribute,
};

#[derive(Clone, Debug)]
pub struct PathParser<'a>(pub Cow<'a, Path>);

impl<'a> PathParser<'a> {
    pub fn get_attribute_path(&self) -> hir::AttrPath {
        AttrPath {
            segments: self.segments().copied().collect::<Vec<_>>().into_boxed_slice(),
            span: self.span(),
        }
    }

    pub fn segments(&'a self) -> impl Iterator<Item = &'a Ident> {
        self.0.segments.iter().map(|seg| &seg.ident)
    }

    pub fn span(&self) -> Span {
        self.0.span
    }

    pub fn len(&self) -> usize {
        self.0.segments.len()
    }

    pub fn segments_is(&self, segments: &[Symbol]) -> bool {
        self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b)
    }

    pub fn word(&self) -> Option<Ident> {
        (self.len() == 1).then(|| **self.segments().next().as_ref().unwrap())
    }

    pub fn word_sym(&self) -> Option<Symbol> {
        self.word().map(|ident| ident.name)
    }

    /// Asserts that this MetaItem is some specific word.
    ///
    /// See [`word`](Self::word) for examples of what a word is.
    pub fn word_is(&self, sym: Symbol) -> bool {
        self.word().map(|i| i.name == sym).unwrap_or(false)
    }

    /// Checks whether the first segments match the givens.
    ///
    /// Unlike [`segments_is`](Self::segments_is),
    /// `self` may contain more segments than the number matched  against.
    pub fn starts_with(&self, segments: &[Symbol]) -> bool {
        segments.len() < self.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b)
    }
}

impl Display for PathParser<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", pprust::path_to_string(&self.0))
    }
}

#[derive(Clone, Debug)]
#[must_use]
pub enum ArgParser<'a> {
    NoArgs,
    List(MetaItemListParser<'a>),
    NameValue(NameValueParser),
}

impl<'a> ArgParser<'a> {
    pub fn span(&self) -> Option<Span> {
        match self {
            Self::NoArgs => None,
            Self::List(l) => Some(l.span),
            Self::NameValue(n) => Some(n.value_span.with_lo(n.eq_span.lo())),
        }
    }

    pub fn from_attr_args<'sess>(
        value: &'a AttrArgs,
        parts: &[Symbol],
        psess: &'sess ParseSess,
        should_emit: ShouldEmit,
    ) -> Option<Self> {
        Some(match value {
            AttrArgs::Empty => Self::NoArgs,
            AttrArgs::Delimited(args) => {
                // The arguments of rustc_dummy are not validated if the arguments are delimited
                if parts == &[sym::rustc_dummy] {
                    return Some(ArgParser::List(MetaItemListParser {
                        sub_parsers: ThinVec::new(),
                        span: args.dspan.entire(),
                    }));
                }

                if args.delim != Delimiter::Parenthesis {
                    psess.dcx().emit_err(MetaBadDelim {
                        span: args.dspan.entire(),
                        sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
                    });
                    return None;
                }

                Self::List(MetaItemListParser::new(args, psess, should_emit)?)
            }
            AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
                eq_span: *eq_span,
                value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
                value_span: expr.span,
            }),
        })
    }

    /// Asserts that this MetaItem is a list
    ///
    /// Some examples:
    ///
    /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list
    /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list
    pub fn list(&self) -> Option<&MetaItemListParser<'a>> {
        match self {
            Self::List(l) => Some(l),
            Self::NameValue(_) | Self::NoArgs => None,
        }
    }

    /// Asserts that this MetaItem is a name-value pair.
    ///
    /// Some examples:
    ///
    /// - `#[clippy::cyclomatic_complexity = "100"]`: `clippy::cyclomatic_complexity = "100"` is a name value pair,
    ///   where the name is a path (`clippy::cyclomatic_complexity`). You already checked the path
    ///   to get an `ArgParser`, so this method will effectively only assert that the `= "100"` is
    ///   there
    /// - `#[doc = "hello"]`: `doc = "hello`  is also a name value pair
    pub fn name_value(&self) -> Option<&NameValueParser> {
        match self {
            Self::NameValue(n) => Some(n),
            Self::List(_) | Self::NoArgs => None,
        }
    }

    /// Assert that there were no args.
    /// If there were, get a span to the arguments
    /// (to pass to [`AcceptContext::expected_no_args`](crate::context::AcceptContext::expected_no_args)).
    pub fn no_args(&self) -> Result<(), Span> {
        match self {
            Self::NoArgs => Ok(()),
            Self::List(args) => Err(args.span),
            Self::NameValue(args) => Err(args.eq_span.to(args.value_span)),
        }
    }
}

/// Inside lists, values could be either literals, or more deeply nested meta items.
/// This enum represents that.
///
/// Choose which one you want using the provided methods.
#[derive(Debug, Clone)]
pub enum MetaItemOrLitParser<'a> {
    MetaItemParser(MetaItemParser<'a>),
    Lit(MetaItemLit),
    Err(Span, ErrorGuaranteed),
}

impl<'a> MetaItemOrLitParser<'a> {
    pub fn span(&self) -> Span {
        match self {
            MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => {
                generic_meta_item_parser.span()
            }
            MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
            MetaItemOrLitParser::Err(span, _) => *span,
        }
    }

    pub fn lit(&self) -> Option<&MetaItemLit> {
        match self {
            MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
            _ => None,
        }
    }

    pub fn meta_item(&self) -> Option<&MetaItemParser<'a>> {
        match self {
            MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
            _ => None,
        }
    }
}

/// Utility that deconstructs a MetaItem into usable parts.
///
/// MetaItems are syntactically extremely flexible, but specific attributes want to parse
/// them in custom, more restricted ways. This can be done using this struct.
///
/// MetaItems consist of some path, and some args. The args could be empty. In other words:
///
/// - `name` -> args are empty
/// - `name(...)` -> args are a [`list`](ArgParser::list), which is the bit between the parentheses
/// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the
///   `= value` part
///
/// The syntax of MetaItems can be found at <https://doc.rust-lang.org/reference/attributes.html>
#[derive(Clone)]
pub struct MetaItemParser<'a> {
    path: PathParser<'a>,
    args: ArgParser<'a>,
}

impl<'a> Debug for MetaItemParser<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MetaItemParser")
            .field("path", &self.path)
            .field("args", &self.args)
            .finish()
    }
}

impl<'a> MetaItemParser<'a> {
    /// Create a new parser from a [`NormalAttr`], which is stored inside of any
    /// [`ast::Attribute`](rustc_ast::Attribute)
    pub fn from_attr<'sess>(
        attr: &'a NormalAttr,
        parts: &[Symbol],
        psess: &'sess ParseSess,
        should_emit: ShouldEmit,
    ) -> Option<Self> {
        Some(Self {
            path: PathParser(Cow::Borrowed(&attr.item.path)),
            args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?,
        })
    }
}

impl<'a> MetaItemParser<'a> {
    pub fn span(&self) -> Span {
        if let Some(other) = self.args.span() {
            self.path.span().with_hi(other.hi())
        } else {
            self.path.span()
        }
    }

    /// Gets just the path, without the args. Some examples:
    ///
    /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path
    /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path
    /// - `#[inline]`: `inline` is a single segment path
    pub fn path(&self) -> &PathParser<'a> {
        &self.path
    }

    /// Gets just the args parser, without caring about the path.
    pub fn args(&self) -> &ArgParser<'a> {
        &self.args
    }

    /// Asserts that this MetaItem starts with a word, or single segment path.
    ///
    /// Some examples:
    /// - `#[inline]`: `inline` is a word
    /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path,
    ///   and not a word and should instead be parsed using [`path`](Self::path)
    pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> {
        self.path().word_is(sym).then(|| self.args())
    }
}

#[derive(Clone)]
pub struct NameValueParser {
    pub eq_span: Span,
    value: MetaItemLit,
    pub value_span: Span,
}

impl Debug for NameValueParser {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("NameValueParser")
            .field("eq_span", &self.eq_span)
            .field("value", &self.value)
            .field("value_span", &self.value_span)
            .finish()
    }
}

impl NameValueParser {
    pub fn value_as_lit(&self) -> &MetaItemLit {
        &self.value
    }

    pub fn value_as_str(&self) -> Option<Symbol> {
        self.value_as_lit().kind.str()
    }
}

fn expr_to_lit(
    psess: &ParseSess,
    expr: &Expr,
    span: Span,
    should_emit: ShouldEmit,
) -> Option<MetaItemLit> {
    if let ExprKind::Lit(token_lit) = expr.kind {
        let res = MetaItemLit::from_token_lit(token_lit, expr.span);
        match res {
            Ok(lit) => {
                if token_lit.suffix.is_some() {
                    should_emit.emit_err(
                        psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
                    );
                    None
                } else {
                    if !lit.kind.is_unsuffixed() {
                        // Emit error and continue, we can still parse the attribute as if the suffix isn't there
                        should_emit.emit_err(
                            psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
                        );
                    }

                    Some(lit)
                }
            }
            Err(err) => {
                let guar = report_lit_error(psess, err, token_lit, expr.span);
                let lit = MetaItemLit {
                    symbol: token_lit.symbol,
                    suffix: token_lit.suffix,
                    kind: LitKind::Err(guar),
                    span: expr.span,
                };
                Some(lit)
            }
        }
    } else {
        if matches!(should_emit, ShouldEmit::Nothing) {
            return None;
        }

        // Example cases:
        // - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
        // - `#[foo = include_str!("nonexistent-file.rs")]`:
        //   results in `ast::ExprKind::Err`. In that case we delay
        //   the error because an earlier error will have already
        //   been reported.
        let msg = "attribute value must be a literal";
        let err = psess.dcx().struct_span_err(span, msg);
        should_emit.emit_err(err);
        None
    }
}

struct MetaItemListParserContext<'a, 'sess> {
    parser: &'a mut Parser<'sess>,
    should_emit: ShouldEmit,
}

impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
    fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
        let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) };
        self.unsuffixed_meta_item_from_lit(token_lit)
    }

    fn unsuffixed_meta_item_from_lit(
        &mut self,
        token_lit: token::Lit,
    ) -> PResult<'sess, MetaItemLit> {
        let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
            Ok(lit) => lit,
            Err(err) => {
                return Err(create_lit_error(
                    &self.parser.psess,
                    err,
                    token_lit,
                    self.parser.prev_token_uninterpolated_span(),
                ));
            }
        };

        if !lit.kind.is_unsuffixed() {
            // Emit error and continue, we can still parse the attribute as if the suffix isn't there
            self.should_emit.emit_err(
                self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
            );
        }

        Ok(lit)
    }

    fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> {
        if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() {
            return if has_meta_form {
                let attr_item = self
                    .parser
                    .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
                        MetaItemListParserContext { parser: this, should_emit: self.should_emit }
                            .parse_attr_item()
                    })
                    .unwrap();
                Ok(attr_item)
            } else {
                self.parser.unexpected_any()
            };
        }

        let path = self.parser.parse_path(PathStyle::Mod)?;

        // Check style of arguments that this meta item has
        let args = if self.parser.check(exp!(OpenParen)) {
            let start = self.parser.token.span;
            let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
                MetaItemListParserContext { parser, should_emit: self.should_emit }
                    .parse_meta_item_inner()
            })?;
            let end = self.parser.prev_token.span;
            ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
        } else if self.parser.eat(exp!(Eq)) {
            let eq_span = self.parser.prev_token.span;
            let value = self.parse_unsuffixed_meta_item_lit()?;

            ArgParser::NameValue(NameValueParser { eq_span, value, value_span: value.span })
        } else {
            ArgParser::NoArgs
        };

        Ok(MetaItemParser { path: PathParser(Cow::Owned(path)), args })
    }

    fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> {
        if let Some(token_lit) = self.parser.eat_token_lit() {
            // If a literal token is parsed, we commit to parsing a MetaItemLit for better errors
            Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
        } else {
            let prev_pros = self.parser.approx_token_stream_pos();
            match self.parse_attr_item() {
                Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
                Err(err) => {
                    // If `parse_attr_item` made any progress, it likely has a more precise error we should prefer
                    // If it didn't make progress we use the `expected_lit` from below
                    if self.parser.approx_token_stream_pos() != prev_pros {
                        Err(err)
                    } else {
                        err.cancel();
                        Err(self.expected_lit())
                    }
                }
            }
        }
    }

    fn expected_lit(&mut self) -> Diag<'sess> {
        let mut err = InvalidMetaItem {
            span: self.parser.token.span,
            descr: token_descr(&self.parser.token),
            quote_ident_sugg: None,
            remove_neg_sugg: None,
        };

        // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
        // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
        // when macro metavariables are involved.
        if self.parser.prev_token == token::Eq
            && let token::Ident(..) = self.parser.token.kind
        {
            let before = self.parser.token.span.shrink_to_lo();
            while let token::Ident(..) = self.parser.token.kind {
                self.parser.bump();
            }
            err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
                before,
                after: self.parser.prev_token.span.shrink_to_hi(),
            });
        }

        if self.parser.token == token::Minus
            && self
                .parser
                .look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
        {
            err.remove_neg_sugg =
                Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });
            self.parser.bump();
            self.parser.bump();
        }

        self.parser.dcx().create_err(err)
    }

    fn parse(
        tokens: TokenStream,
        psess: &'sess ParseSess,
        span: Span,
        should_emit: ShouldEmit,
    ) -> PResult<'sess, MetaItemListParser<'static>> {
        let mut parser = Parser::new(psess, tokens, None);
        let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };

        // Presumably, the majority of the time there will only be one attr.
        let mut sub_parsers = ThinVec::with_capacity(1);
        while this.parser.token != token::Eof {
            sub_parsers.push(this.parse_meta_item_inner()?);

            if !this.parser.eat(exp!(Comma)) {
                break;
            }
        }

        if parser.token != token::Eof {
            parser.unexpected()?;
        }

        Ok(MetaItemListParser { sub_parsers, span })
    }
}

#[derive(Debug, Clone)]
pub struct MetaItemListParser<'a> {
    sub_parsers: ThinVec<MetaItemOrLitParser<'a>>,
    pub span: Span,
}

impl<'a> MetaItemListParser<'a> {
    fn new<'sess>(
        delim: &'a DelimArgs,
        psess: &'sess ParseSess,
        should_emit: ShouldEmit,
    ) -> Option<Self> {
        match MetaItemListParserContext::parse(
            delim.tokens.clone(),
            psess,
            delim.dspan.entire(),
            should_emit,
        ) {
            Ok(s) => Some(s),
            Err(e) => {
                should_emit.emit_err(e);
                None
            }
        }
    }

    /// Lets you pick and choose as what you want to parse each element in the list
    pub fn mixed(&self) -> impl Iterator<Item = &MetaItemOrLitParser<'a>> {
        self.sub_parsers.iter()
    }

    pub fn len(&self) -> usize {
        self.sub_parsers.len()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns Some if the list contains only a single element.
    ///
    /// Inside the Some is the parser to parse this single element.
    pub fn single(&self) -> Option<&MetaItemOrLitParser<'a>> {
        let mut iter = self.mixed();
        iter.next().filter(|_| iter.next().is_none())
    }
}
