import os
from types import SimpleNamespace
from toga.sources import ListSource

import toga
import pytest

from seedpass.core.entry_types import EntryType

from seedpass_gui.app import LockScreenWindow, MainWindow, EntryDialog


class FakeVault:
    def __init__(self):
        self.called = False

    def unlock(self, request):
        self.called = True


class FakeEntries:
    def __init__(self):
        self.added = []
        self.modified = []

    def list_entries(self):
        return []

    def search_entries(self, query, kinds=None):
        return []

    def add_entry(self, label, length, username=None, url=None):
        self.added.append(("password", label, length, username, url))
        return 1

    def add_totp(self, label):
        self.added.append(("totp", label))
        return 1

    def add_ssh_key(self, label):
        self.added.append(("ssh", label))
        return 1

    def add_seed(self, label):
        self.added.append(("seed", label))
        return 1

    def add_pgp_key(self, label):
        self.added.append(("pgp", label))
        return 1

    def add_nostr_key(self, label):
        self.added.append(("nostr", label))
        return 1

    def add_key_value(self, label, key, value):
        self.added.append(("key_value", label, key, value))
        return 1

    def add_managed_account(self, label):
        self.added.append(("managed_account", label))
        return 1

    def modify_entry(
        self, entry_id, username=None, url=None, label=None, key=None, value=None
    ):
        self.modified.append((entry_id, username, url, label, key, value))


def setup_module(module):
    os.environ["TOGA_BACKEND"] = "toga_dummy"
    import asyncio

    asyncio.set_event_loop(asyncio.new_event_loop())


class FakeNostr:
    def list_relays(self):
        return []

    def add_relay(self, url):
        pass

    def remove_relay(self, idx):
        pass


def test_unlock_creates_main_window():
    app = toga.App("Test", "org.example")
    controller = SimpleNamespace(main_window=None, nostr_service=FakeNostr())
    vault = FakeVault()
    entries = FakeEntries()
    win = LockScreenWindow(controller, vault, entries)
    win.password_input.value = "pw"
    win.handle_unlock(None)

    assert vault.called
    assert isinstance(controller.main_window, MainWindow)
    controller.main_window.cleanup()


@pytest.mark.parametrize(
    "kind,expect",
    [
        (EntryType.PASSWORD.value, ("password", "L", 12, "u", "x")),
        (EntryType.TOTP.value, ("totp", "L")),
        (EntryType.SSH.value, ("ssh", "L")),
        (EntryType.SEED.value, ("seed", "L")),
        (EntryType.PGP.value, ("pgp", "L")),
        (EntryType.NOSTR.value, ("nostr", "L")),
        (EntryType.KEY_VALUE.value, ("key_value", "L", "k1", "val")),
        (EntryType.MANAGED_ACCOUNT.value, ("managed_account", "L")),
    ],
)
def test_entrydialog_add_calls_service(kind, expect):
    toga.App("Test2", "org.example2")
    entries = FakeEntries()
    entries.retrieve_entry = lambda _id: {"kind": kind}
    source = ListSource(["id", "label", "kind", "info1", "info2"])
    main = SimpleNamespace(entries=entries, entry_source=source)

    dlg = EntryDialog(main, None)
    dlg.label_input.value = "L"
    dlg.kind_input.value = kind
    dlg.username_input.value = "u"
    dlg.url_input.value = "x"
    dlg.length_input.value = 12
    dlg.key_input.value = "k1"
    dlg.value_input.value = "val"
    dlg.save(None)

    assert entries.added[-1] == expect
    assert len(main.entry_source) == 1
    row = main.entry_source[0]
    assert row.label == "L"
    assert row.kind == kind


@pytest.mark.parametrize(
    "kind,expected",
    [
        (EntryType.PASSWORD.value, (1, "newu", "newx", "New", None, None)),
        (EntryType.KEY_VALUE.value, (1, None, None, "New", "k2", "val2")),
        (EntryType.TOTP.value, (1, None, None, "New", None, None)),
    ],
)
def test_entrydialog_edit_calls_service(kind, expected):
    toga.App("Edit", "org.edit")
    entries = FakeEntries()

    def retrieve(_id):
        return {"kind": kind}

    entries.retrieve_entry = retrieve
    source = ListSource(["id", "label", "kind", "info1", "info2"])
    source.append({"id": 1, "label": "Old", "kind": kind, "info1": "", "info2": ""})
    main = SimpleNamespace(entries=entries, entry_source=source)
    dlg = EntryDialog(main, 1)
    dlg.label_input.value = "New"
    dlg.kind_input.value = kind
    dlg.username_input.value = "newu"
    dlg.url_input.value = "newx"
    dlg.key_input.value = "k2"
    dlg.value_input.value = "val2"
    dlg.save(None)

    assert entries.modified[-1] == expected
    assert source[0].label == "New"
