import pytest

from imapsync_bulk.accounts import AccountFileError, load_accounts, parse_accounts

# Extrait litteral de examples/file.txt du depot imapsync.
OFFICIAL_SAMPLE = """\
# Example file.txt for imapsync massive migration.
#
# Each line contains at least 6 columns
# The separator is the character semi-colon ";"

# Now the data example
host001_1;user001_1;password001_1;host001_2;user001_2;password001_2;;
host002_1;user002_1;password002_1;host002_2;user002_2;password002_2;--subfolder2 foo;
host003_1;user003_1;password003_1;host003_2;user003_2;password003_2;--justfolders --automap --subfolder2 foo;

# Another comment blabla
host004_1;user004_1;password004_1;host004_2;user004_2;password004_2;;

test1.lamiral.info;test1;secret1;test2.lamiral.info;test2;secret2;;

# The reverse with some extra parameters
test2.lamiral.info;test2;secret2;test1.lamiral.info;test1;secret1;--dry --subfolder2 foo --exclude "toto tata" ;
"""


def test_parses_the_official_example_file():
    accounts = parse_accounts(OFFICIAL_SAMPLE)
    assert len(accounts) == 6


def test_columns_map_to_the_documented_parameters():
    (account,) = parse_accounts("h1;u1;p1;h2;u2;p2;;")
    assert account.host1 == "h1"
    assert account.user1 == "u1"
    assert account.password1 == "p1"
    assert account.host2 == "h2"
    assert account.user2 == "u2"
    assert account.password2 == "p2"
    assert account.extra == []


def test_comments_and_blank_lines_are_ignored():
    text = "# commentaire\n\n   \nh1;u1;p1;h2;u2;p2;;\n# encore\n"
    assert len(parse_accounts(text)) == 1


def test_extra_column_is_split_like_a_shell():
    (account,) = parse_accounts(
        'h1;u1;p1;h2;u2;p2;--justfolders --automap --exclude "toto tata";'
    )
    assert account.extra == [
        "--justfolders",
        "--automap",
        "--exclude",
        "toto tata",
    ]


def test_trailing_semicolon_is_optional():
    without = parse_accounts("h1;u1;p1;h2;u2;p2")
    with_it = parse_accounts("h1;u1;p1;h2;u2;p2;")
    assert without[0].host1 == with_it[0].host1 == "h1"
    assert without[0].extra == with_it[0].extra == []


def test_line_numbers_are_preserved_for_diagnostics():
    text = "# tete\n\nh1;u1;p1;h2;u2;p2;;\nh3;u3;p3;h4;u4;p4;;\n"
    accounts = parse_accounts(text)
    assert [a.line_number for a in accounts] == [3, 4]


def test_too_few_columns_names_the_line():
    with pytest.raises(AccountFileError, match="ligne 2"):
        parse_accounts("h1;u1;p1;h2;u2;p2;;\nh1;u1;p1;h2;u2\n")


def test_empty_mandatory_column_is_rejected():
    with pytest.raises(AccountFileError, match="password1"):
        parse_accounts("h1;u1;;h2;u2;p2;;")


def test_unbalanced_quote_in_extra_is_reported():
    with pytest.raises(AccountFileError, match="extra"):
        parse_accounts('h1;u1;p1;h2;u2;p2;--exclude "pas ferme;')


def test_password_containing_spaces_is_preserved():
    (account,) = parse_accounts("h1;u1;mot de passe;h2;u2;p2;;")
    assert account.password1 == "mot de passe"


def test_label_is_readable():
    (account,) = parse_accounts("srv1;alice;p;srv2;bob;p;;")
    assert account.label == "alice → bob  (srv1 → srv2)"


def test_label_is_compact_when_the_user_is_the_same():
    (account,) = parse_accounts("srv1;alice@x.fr;p;srv2;alice@x.fr;p;;")
    assert account.label == "alice@x.fr  (srv1 → srv2)"


def test_label_survives_rich_markup():
    """Rich effacerait un « [x] » en le prenant pour une balise de style."""
    (account,) = parse_accounts("srv1;alice;p;srv2;bob;p;;")
    assert "[" not in account.label


def test_slug_is_filesystem_safe():
    (account,) = parse_accounts("srv1;alice@example.com;p;srv2;bob;p;;")
    assert "/" not in account.slug
    assert account.slug.startswith("alice@example.com")


def test_load_accounts_rejects_an_empty_file(tmp_path):
    path = tmp_path / "vide.txt"
    path.write_text("# que des commentaires\n")
    with pytest.raises(AccountFileError, match="aucun compte"):
        load_accounts(path)


def test_load_accounts_reports_a_missing_file(tmp_path):
    with pytest.raises(AccountFileError, match="illisible"):
        load_accounts(tmp_path / "absent.txt")
