use rustc_feature::AttributeStability;
use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType};

use super::prelude::*;

pub(crate) struct DebuggerVisualizerParser;

impl CombineAttributeParser for DebuggerVisualizerParser {
    const PATH: &[Symbol] = &[sym::debugger_visualizer];
    const ALLOWED_TARGETS: AllowedTargets =
        AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
    const TEMPLATE: AttributeTemplate = template!(
        List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
        "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
    );
    const STABILITY: AttributeStability = AttributeStability::Stable;

    type Item = DebugVisualizer;
    const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v);

    fn extend(
        cx: &mut AcceptContext<'_, '_>,
        args: &ArgParser,
    ) -> impl IntoIterator<Item = Self::Item> {
        let single = cx.expect_single_element_list(args, cx.attr_span)?;
        let (ident, args) = cx.expect_name_value(single, single.span(), None)?;
        let visualizer_type = match ident.name {
            sym::natvis_file => DebuggerVisualizerType::Natvis,
            sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter,
            _ => {
                cx.adcx().expected_specific_argument(
                    ident.span,
                    &[sym::natvis_file, sym::gdb_script_file],
                );
                return None;
            }
        };

        let path = cx.expect_string_literal(args)?;

        Some(DebugVisualizer { span: ident.span.to(args.value_span), visualizer_type, path })
    }
}
