use crate::{
    assert_parsing_eq,
    attribute::{
        r#type::{ConfigType, Type},
        AndExpression, Atom, DefaultAttribute, Expression, Term,
    },
    entry::{parse_config, Config},
    symbol::{ConstantSymbol, Symbol},
    Attribute,
};

#[test]
fn test_parse_config() {
    let input = "config KVM hex \"wow\"";
    assert_parsing_eq!(
        parse_config,
        input,
        Ok((
            "",
            Config {
                symbol: "KVM".to_string(),
                attributes: vec!(Attribute::Type(ConfigType {
                    r#type: Type::Hex(Some("wow".to_string())),
                    r#if: None
                }))
            }
        ))
    )
}

// 6.4.9/init/Kconfig
#[test]
fn test_parse_config_no_type() {
    let input = "config ARCH_MMAP_RND_BITS_MIN
	default 18 if 64BIT
	default 8";
    assert_parsing_eq!(
        parse_config,
        input,
        Ok((
            "",
            Config {
                symbol: "ARCH_MMAP_RND_BITS_MIN".to_string(),
                attributes: vec!(
                    Attribute::Default(DefaultAttribute {
                        expression: Expression::Term(AndExpression::Term(Term::Atom(
                            Atom::Symbol(Symbol::Constant(ConstantSymbol::Integer(18)))
                        ))),
                        r#if: Some(Expression::Term(AndExpression::Term(Term::Atom(
                            Atom::Symbol(Symbol::NonConstant("64BIT".to_string()))
                        ))))
                    }),
                    Attribute::Default(DefaultAttribute {
                        expression: Expression::Term(AndExpression::Term(Term::Atom(
                            Atom::Symbol(Symbol::Constant(ConstantSymbol::Integer(8)))
                        ))),
                        r#if: None
                    })
                )
            }
        ))
    )
}

#[test]
fn test_parse_config_tristate() {
    let input = "config RAPIDIO_ENUM_BASIC\n    tristate";
    assert_parsing_eq!(
        parse_config,
        input,
        Ok((
            "",
            Config {
                symbol: "RAPIDIO_ENUM_BASIC".to_string(),
                attributes: vec!(Attribute::Type(ConfigType {
                    r#type: Type::Tristate(None),
                    r#if: None
                }))
            }
        ))
    )
}

// 6.4.9/arch/sh/Kconfig
#[test]
fn test_parse_config_def_bool_multiline_expression() {
    let input = "config SH_CLK_CPG_LEGACY
	depends on SH_CLK_CPG
	def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
		      !CPU_SHX3 && !CPU_SUBTYPE_SH7757 && \
		      !CPU_SUBTYPE_SH7734 && !CPU_SUBTYPE_SH7264 && \
		      !CPU_SUBTYPE_SH7269";
    assert_parsing_eq!(
        parse_config,
        input,
        Ok((
            "",
            Config {
                symbol: "SH_CLK_CPG_LEGACY".to_string(),
                attributes: vec!(
                    Attribute::DependsOn(Expression::Term(AndExpression::Term(Term::Atom(
                        Atom::Symbol(Symbol::NonConstant("SH_CLK_CPG".to_string()))
                    )))),
                    Attribute::Type(ConfigType {
                        r#type: Type::DefBool(Expression::Term(AndExpression::Term(Term::Atom(
                            Atom::Symbol(Symbol::Constant(ConstantSymbol::Boolean(true)))
                        )))),
                        r#if: Some(Expression::Term(AndExpression::Expression(vec!(
                            Term::Not(Atom::Symbol(Symbol::NonConstant(
                                "CPU_SUBTYPE_SH7785".to_string()
                            ))),
                            Term::Not(Atom::Symbol(Symbol::NonConstant(
                                "ARCH_SHMOBILE".to_string()
                            ))),
                            Term::Not(Atom::Symbol(Symbol::NonConstant("CPU_SHX3".to_string()))),
                            Term::Not(Atom::Symbol(Symbol::NonConstant(
                                "CPU_SUBTYPE_SH7757".to_string()
                            ))),
                            Term::Not(Atom::Symbol(Symbol::NonConstant(
                                "CPU_SUBTYPE_SH7734".to_string()
                            ))),
                            Term::Not(Atom::Symbol(Symbol::NonConstant(
                                "CPU_SUBTYPE_SH7264".to_string()
                            ))),
                            Term::Not(Atom::Symbol(Symbol::NonConstant(
                                "CPU_SUBTYPE_SH7269".to_string()
                            ))),
                        ))))
                    }),
                )
            }
        ))
    )
}

#[test]
fn test_parse_config_bootparam_string() {
    let input = "config BOOTPARAM_STRING
	string 'Kernel Boot Parameter'
	default 'console=ttyS0,19200'
	depends on BOOTPARAM";
    assert_parsing_eq!(
        parse_config,
        input,
        Ok((
            "",
            Config {
                symbol: "BOOTPARAM_STRING".to_string(),
                attributes: vec!(
                    Attribute::Type(ConfigType {
                        r#type: Type::String(Some("Kernel Boot Parameter".to_string())),
                        r#if: None
                    }),
                    Attribute::Default(DefaultAttribute {
                        expression: Expression::Term(AndExpression::Term(Term::Atom(
                            Atom::Symbol(Symbol::Constant(ConstantSymbol::String(
                                "console=ttyS0,19200".to_string()
                            )))
                        ))),
                        r#if: None
                    }),
                    Attribute::DependsOn(Expression::Term(AndExpression::Term(Term::Atom(
                        Atom::Symbol(Symbol::NonConstant("BOOTPARAM".to_string()))
                    )))),
                )
            }
        ))
    )
}

/// https://github.com/nrfconnect/sdk-zephyr/blob/d947269643dd51e4e95d35d148cecb40562fe0d2/modules/tflite-micro/Kconfig#L5
#[test]
fn test_parse_config_name_with_hyphen() {
    let input = "config ZEPHYR_TFLITE-MICRO_MODULE
	bool";
    assert_parsing_eq!(
        parse_config,
        input,
        Ok((
            "",
            Config {
                symbol: "ZEPHYR_TFLITE-MICRO_MODULE".to_string(),
                attributes: vec!(Attribute::Type(ConfigType {
                    r#type: Type::Bool(None),
                    r#if: None
                }),)
            }
        ))
    )
}
