from email.parser import BytesParser
from email.policy import default

import pytest

pytest.importorskip("tkinter")

from ccma.config import AppConfig  # noqa: E402
from ccma.domain.mail_templates import placeholder_entries  # noqa: E402
from ccma.services.welcome_mail import generate_and_send_welcome_mail  # noqa: E402
from ccma.storage.repository import MemberRepository, RepositoryError  # noqa: E402


@pytest.fixture
def repository(tmp_path):
    repository = MemberRepository(tmp_path / "store")
    repository.initialize()
    organization = repository.get_configuration()["organization"]
    organization.update(
        {
            "name": "Chaos Computer Club Mannheim e.V.",
            "email": "verwaltung@example.org",
            "iban": "DE98670505050038907751",
            "bic": "MANSDE66XXX",
        }
    )
    repository.save_organization(organization)
    return repository


def _open_options(tk_root, repository):
    from ccma.ui.options_dialog import OptionsDialog

    dialog = OptionsDialog(tk_root, AppConfig(store_path=str(repository.root)), repository)
    tk_root.update()
    return dialog


def _block_row(dialog):
    for row in dialog.mail_template_placeholders.get_children():
        label = str(dialog.mail_template_placeholders.item(row, "values")[0])
        if label.startswith("{{#claims}}"):
            return row
    raise AssertionError("Der Wiederholungsblock fehlt in der Platzhalterliste.")


def test_double_click_on_a_block_is_wired_up(tk_root, repository):
    dialog = _open_options(tk_root, repository)
    try:
        assert dialog.mail_template_placeholders.bind("<Double-1>")
        assert dialog.mail_template_snippets[_block_row(dialog)] == next(
            entry.snippet
            for entry in placeholder_entries("welcome")
            if entry.label.startswith("{{#claims}}")
        )
    finally:
        dialog.grab_release()
        dialog.destroy()


def test_inserting_a_block_puts_editable_template_code_into_the_body(tk_root, repository):
    dialog = _open_options(tk_root, repository)
    try:
        dialog.mail_template_body.delete("1.0", "end")
        dialog.mail_template_body.insert("1.0", "Offen sind aktuell:")
        dialog.mail_template_placeholders.selection_set(_block_row(dialog))
        dialog._insert_mail_placeholder()
        tk_root.update()
        body = dialog.mail_template_body.get("1.0", "end-1c")
    finally:
        dialog.grab_release()
        dialog.destroy()

    assert "…" not in body
    assert "{{#claims}}" in body and "{{/claims}}" in body
    assert "{{claim.description}}" in body
    # The block was appended behind existing text and still starts on its own line.
    assert body.splitlines()[0] == "Offen sind aktuell:"
    assert body.splitlines()[1] == "{{#claims}}"


def test_edited_template_survives_saving_and_produces_real_lines_in_the_mail(
    tk_root, repository, tmp_path
):
    member = repository.create_member(
        first_name="Ada", last_name="Lovelace", birth_date="1990-01-01"
    )
    member.email = "ada@example.org"
    member.accepted_at = "2026-08-20"
    repository.save_member(member)
    repository.create_manual_claim(
        member.member_id, title="Aufnahmegebühr", amount="15.00", due_date="2026-09-17"
    )

    dialog = _open_options(tk_root, repository)
    try:
        dialog.mail_template_subject_var.set("Willkommen, {{member.first_name}}")
        dialog.mail_template_body.delete("1.0", "end")
        dialog.mail_template_body.insert("1.0", "Offen sind aktuell:\n")
        dialog.mail_template_placeholders.selection_set(_block_row(dialog))
        dialog._insert_mail_placeholder()
        tk_root.update()
        dialog._save_mail_templates()
    finally:
        dialog.grab_release()
        dialog.destroy()

    generated = generate_and_send_welcome_mail(
        repository,
        member.member_id,
        delivery_mode="local",
        output_path=tmp_path / "Willkommen.eml",
        sender_name="Verwaltung C3MA",
        sender_email="verwaltung@example.org",
        signature="Der Vorstand",
    )

    content = BytesParser(policy=default).parsebytes(
        generated.export_path.read_bytes()
    ).get_content()
    assert "Aufnahmegebühr (fällig 17.09.2026): 15.00 Euro" in content
    assert "…" not in content


def test_the_dialog_refuses_to_save_an_unbalanced_block(tk_root, repository):
    stored = repository.mail_templates_root / "willkommen.txt"
    before = stored.read_text(encoding="utf-8")

    dialog = _open_options(tk_root, repository)
    try:
        dialog.mail_template_body.delete("1.0", "end")
        dialog.mail_template_body.insert("1.0", "Offen sind aktuell:\n{{#claims}}\n{{claim.title}}")
        with pytest.raises(RepositoryError, match="wird nicht geschlossen"):
            dialog._save_mail_templates()
    finally:
        dialog.grab_release()
        dialog.destroy()

    assert stored.read_text(encoding="utf-8") == before


def test_a_broken_template_does_not_half_save_the_others(tk_root, repository):
    reminder_file = repository.mail_templates_root / "mahnung.txt"
    before = reminder_file.read_text(encoding="utf-8")

    dialog = _open_options(tk_root, repository)
    try:
        # Edit a valid template first, then break the second one.
        dialog.mail_template_var.set("Mahnung")
        dialog._select_mail_template()
        dialog.mail_template_body.insert("end", "\nP.S. Bitte Mitgliedsnummer angeben.")
        dialog.mail_template_var.set("Willkommen & Erstrechnung")
        dialog._select_mail_template()
        dialog.mail_template_body.insert("end", "\n{{#claims}}\n{{claim.title}}")
        with pytest.raises(RepositoryError, match="wird nicht geschlossen"):
            dialog._save_mail_templates()
    finally:
        dialog.grab_release()
        dialog.destroy()

    assert reminder_file.read_text(encoding="utf-8") == before
