import pytest
from journalcheck.config import (
    DEFAULT_VIOLATIONS,
    Config,
    IdentifierConfig,
    PRIORITY_NAMES,
    ConfigKeys,
    IdentifierConfigKeys,
    OutputFormat,
)


def test_normalize_priority_string():
    assert PRIORITY_NAMES["warning"] == 4
    assert PRIORITY_NAMES["info"] == 6


def test_normalize_priority_int():
    config = Config(priority=3)
    assert config.priority == 3


def test_identifier_config_invalid_priority():
    with pytest.raises(ValueError, match="Priority must be 0-7"):
        IdentifierConfig(priority=10)


def test_identifier_config_invalid_regex():
    with pytest.raises(ValueError, match="Invalid regex pattern"):
        IdentifierConfig(ignore=["[invalid"])


def test_identifier_config_invalid_regex_in_violations():
    with pytest.raises(ValueError, match="Invalid regex pattern"):
        IdentifierConfig(violations=["[invalid"])


def test_identifier_config_invalid_ignore():
    with pytest.raises(ValueError, match="ignore must be a list"):
        IdentifierConfig(ignore={"key": "value"})


def test_identifier_config_invalid_violations():
    with pytest.raises(ValueError, match="violations must be a list"):
        IdentifierConfig(violations={"key": "value"})


def test_config_invalid_priority():
    with pytest.raises(ValueError, match="Priority must be 0-7"):
        Config(priority=8)

def test_config_invalid_identifier_priority():
    with pytest.raises(ValueError, match="Priority must be 0-7"):
        Config(identifiers={"test": IdentifierConfig(priority=10)})


def test_config_invalid_regex_identifier():
    with pytest.raises(ValueError, match="Invalid regex identifier"):
        Config(identifiers={"/[invalid/": IdentifierConfig(priority=4)})


def test_identifier_config_from_dict():
    data = {
        IdentifierConfigKeys.PRIORITY: "warning",
        IdentifierConfigKeys.IGNORE: [".*test.*"],
        IdentifierConfigKeys.VIOLATIONS: ["fail"],
    }
    config = IdentifierConfig.from_dict(data)
    assert config.priority == 4
    assert config.ignore == [".*test.*"]
    assert config.violations == ["fail"]


def test_config_from_dict():
    data = {
        ConfigKeys.PRIORITY: "err",
        ConfigKeys.FORMAT: OutputFormat.JSON,
        ConfigKeys.IDENTIFIERS: {
            "ssh": {
                IdentifierConfigKeys.PRIORITY: 6,
                IdentifierConfigKeys.VIOLATIONS: ["BREAK-IN"],
            },
            "kernel": {IdentifierConfigKeys.PRIORITY: 3},
        },
    }
    config = Config.from_dict(data)
    assert config.priority == 3
    assert config.format == OutputFormat.JSON
    assert isinstance(config.identifiers["ssh"], IdentifierConfig)
    assert config.identifiers["ssh"].priority == 6
    assert isinstance(config.identifiers["kernel"], IdentifierConfig)
    assert config.identifiers["kernel"].priority == 3


def test_config_unknown_key():
    with pytest.raises(ValueError, match="Unknown keys in config: unknown_key"):
        Config.from_dict({ConfigKeys.PRIORITY: 6, "unknown_key": "value"})


def test_config_unknown_priority():
    with pytest.raises(ValueError, match="Unknown priority"):
        Config.from_dict({"priority": "invalid"})


def test_config_invalid_format():
    with pytest.raises(ValueError, match="Format must be"):
        Config.from_dict({"format": "invalid"})


def test_identifier_config_unknown_key():
    with pytest.raises(
        ValueError, match="Unknown keys in identifier config: unknown_key"
    ):
        IdentifierConfig.from_dict(
            {IdentifierConfigKeys.PRIORITY: 6, "unknown_key": "value"}
        )


def test_identifier_config_to_dict():
    config = IdentifierConfig(priority=4, ignore=["test"], violations=["fail"])
    result = config.to_dict()
    assert result[IdentifierConfigKeys.PRIORITY] == "warning"
    assert result[IdentifierConfigKeys.IGNORE] == ["test"]
    assert result[IdentifierConfigKeys.VIOLATIONS] == ["fail"]

    # Test with no priority set (should not include priority in output)
    config_no_priority = IdentifierConfig(ignore=["test"], violations=["fail"])
    result_no_priority = config_no_priority.to_dict()
    assert IdentifierConfigKeys.PRIORITY not in result_no_priority
    assert result_no_priority[IdentifierConfigKeys.IGNORE] == ["test"]
    assert result_no_priority[IdentifierConfigKeys.VIOLATIONS] == ["fail"]


def test_config_to_dict():
    config = Config(
        priority=3,
        format=OutputFormat.JSON,
        cursor_file="/tmp/cursor",
        output_command="echo test",
        email_to="admin@example.com",
        email_subject="Test Alert",
        identifiers={"ssh": IdentifierConfig(priority=6, violations=["Failed"])},
    )
    result = config.to_dict()
    assert result[ConfigKeys.PRIORITY] == "err"
    assert result[ConfigKeys.FORMAT] == OutputFormat.JSON
    assert result[ConfigKeys.CURSOR_FILE] == "/tmp/cursor"
    assert result[ConfigKeys.OUTPUT_COMMAND] == "echo test"
    assert result[ConfigKeys.EMAIL_TO] == "admin@example.com"
    assert result[ConfigKeys.EMAIL_SUBJECT] == "Test Alert"
    assert result[ConfigKeys.IDENTIFIERS]["ssh"][IdentifierConfigKeys.PRIORITY] == "info"
    assert result[ConfigKeys.IDENTIFIERS]["ssh"][IdentifierConfigKeys.VIOLATIONS] == [
        "Failed"
    ]


def test_config_to_dict_with_regex_identifier():
    config = Config(
        priority=6,
        identifiers={
            "ssh": IdentifierConfig(priority=4),
            "/^systemd.*/": IdentifierConfig(priority=3, ignore=["test"]),
        },
    )
    result = config.to_dict()
    assert "ssh" in result[ConfigKeys.IDENTIFIERS]
    assert "/^systemd.*/" in result[ConfigKeys.IDENTIFIERS]
    assert (
        result[ConfigKeys.IDENTIFIERS]["ssh"][IdentifierConfigKeys.PRIORITY]
        == "warning"
    )
    assert (
        result[ConfigKeys.IDENTIFIERS]["/^systemd.*/"][IdentifierConfigKeys.PRIORITY]
        == "err"
    )
    assert result[ConfigKeys.IDENTIFIERS]["/^systemd.*/"][
        IdentifierConfigKeys.IGNORE
    ] == ["test"]


def test_default_violations_sshd():
    config = Config.from_dict(
        {
            ConfigKeys.IDENTIFIERS: {
                "sshd": {},
                "kernel": {IdentifierConfigKeys.VIOLATIONS: ["test_violation"]},
            }
        }
    )
    assert len(config.identifiers["sshd"].violations) > 0
    assert any("Failed password" in v for v in config.identifiers["sshd"].violations)

    assert len(config.identifiers["kernel"].violations) > 1
    assert any("test_violation" in v for v in config.identifiers["kernel"].violations)

    for ident in DEFAULT_VIOLATIONS:
        assert len(config.identifiers[ident].violations) > 0


def test_default_violations_with_custom():
    config = Config.from_dict(
        {
            ConfigKeys.IDENTIFIERS: {
                "sshd": {IdentifierConfigKeys.VIOLATIONS: ["custom pattern"]}
            }
        }
    )
    violations = config.identifiers["sshd"].violations
    assert "custom pattern" in violations
    assert any("Failed password" in v for v in violations)
    assert len(violations) > 1


def test_config_invalid_cursor_file_type():
    with pytest.raises(ValueError, match="cursor_file must be a string"):
        Config.from_dict({ConfigKeys.CURSOR_FILE: 123})


def test_config_invalid_output_command_type():
    with pytest.raises(ValueError, match="output_command must be a string"):
        Config.from_dict({ConfigKeys.OUTPUT_COMMAND: ["list", "not", "string"]})


def test_config_invalid_email_to_type():
    with pytest.raises(ValueError, match="email_to must be a string"):
        Config.from_dict({ConfigKeys.EMAIL_TO: 123})


def test_config_invalid_email_subject_type():
    with pytest.raises(ValueError, match="email_subject must be a string"):
        Config.from_dict({ConfigKeys.EMAIL_SUBJECT: True})


def test_identifier_config_invalid_priority_string():
    with pytest.raises(
        ValueError, match="Unknown priority 'invalid' for identifier 'test'"
    ):
        IdentifierConfig.from_dict(
            {IdentifierConfigKeys.PRIORITY: "invalid"}, identifier="test"
        )


def test_identifier_config_invalid_ignore_item_type():
    with pytest.raises(
        ValueError, match="All ignore patterns must be strings for identifier 'test'"
    ):
        IdentifierConfig.from_dict(
            {IdentifierConfigKeys.IGNORE: ["valid", 123, "another"]}, identifier="test"
        )


def test_identifier_config_invalid_violations_item_type():
    with pytest.raises(
        ValueError, match="All violations must be strings for identifier 'test'"
    ):
        IdentifierConfig.from_dict(
            {IdentifierConfigKeys.VIOLATIONS: ["valid", None, "another"]},
            identifier="test",
        )
