# © 2021 Florian Kantelberg - initOS GmbH
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import json
import logging
from uuid import uuid4

from odoo.exceptions import UserError
from odoo.tests import TransactionCase

_logger = logging.getLogger(__name__)


TestChild = {
    "uuid": "42a",
    "note": "test note child",
    "name": "test child",
    "url": "child.example.org",
    "fields": [],
    "files": [],
    "childs": [],
}

TestData = [
    {
        "uuid": "42b",
        "note": "test note child",
        "name": "don't import",
        "url": "child.example.org",
        "fields": [],
        "files": [],
        "childs": [],
    },
    TestChild,
    {
        "uuid": "42",
        "note": "test note",
        "name": "test name",
        "url": "test.example.org",
        "fields": [
            {"name": "a", "value": "Hello World", "iv": "abcd"},
            {"name": "secret", "value": "dlrow olleh", "iv": "abcd"},
            {"name": "secret", "value": "dlrow olle", "iv": "abcd"},
        ],
        "files": [
            {"name": "a", "value": "Hello World", "iv": "abcd"},
            {"name": "secret", "value": "dlrow olleh", "iv": "abcd"},
            {},
        ],
        "childs": [
            {
                "uuid": "42aa",
                "note": "test note subchild",
                "name": "test subchild",
                "url": "subchild.example.org",
                "fields": [],
                "files": [],
                "childs": [],
            },
            TestChild,
        ],
    },
    TestChild,
]


class TestWidgets(TransactionCase):
    def setUp(self):
        super().setUp()

        self.vault = self.env["vault"].create({"name": "Vault"})
        self.entry = self.env["vault.entry"].create(
            {"vault_id": self.vault.id, "name": "Entry"}
        )

    def test_path_generation(self):
        wiz = self.env["vault.import.wizard"].create(
            {"vault_id": self.vault.id, "crypted_content": json.dumps(TestData)}
        )
        wiz._onchange_content()

        paths = wiz.path.search([("uuid", "=", wiz.uuid)]).mapped("name")

        self.assertEqual(len(paths), 6)
        self.assertIn("test name / test child", paths)
        self.assertIn("test child", paths)
        self.assertIn("test name", paths)

    def test_import(self):
        uuid = uuid4()
        path = self.env["vault.import.wizard.path"].create(
            {"name": "test", "uuid": uuid}
        )

        wiz = self.env["vault.import.wizard"].create(
            {
                "vault_id": self.vault.id,
                "crypted_content": json.dumps(TestData),
                "path": path.id,
                "uuid": uuid,
            }
        )

        wiz.action_import()

        # We have duplicates
        uuids = {"42", "42a", "42aa", self.entry.uuid}
        self.assertSetEqual(set(self.vault.entry_ids.mapped("uuid")), uuids)

        # Creation is depth-first which will cause the 42a to move up
        self.assertEqual(self.vault.entry_ids.mapped("child_ids.uuid"), ["42aa"])

        # This will cause an overwrite of the field
        domain = [("entry_id.uuid", "=", "42"), ("name", "=", "secret")]
        rec = self.env["vault.field"].search(domain)
        self.assertEqual(rec.mapped("value"), ["dlrow olle"])

        # Field with missing keys should fail
        with self.assertRaises(UserError):
            TestChild["fields"].append({"name": "12", "value": "eulav"})
            wiz.crypted_content = json.dumps([TestChild])
            wiz.action_import()

    def test_export(self):
        child = self.env["vault.entry"].create(
            {"vault_id": self.vault.id, "name": "Child", "parent_id": self.entry.id}
        )

        second = self.env["vault.entry"].create(
            {"vault_id": self.vault.id, "name": "second"}
        )

        wiz = self.env["vault.export.wizard"].create({"vault_id": self.vault.id})

        # Export without entry should export entire vault
        wiz._onchange_content()
        entries = json.loads(wiz.content)
        self.assertEqual({e["uuid"] for e in entries}, {second.uuid, self.entry.uuid})
        self.assertEqual(len(entries), 2)

        wiz.entry_id = self.entry

        # Export the entire tree
        wiz._onchange_content()
        entries = json.loads(wiz.content)
        self.assertEqual(len(entries), 1)
        self.assertEqual(entries[0]["uuid"], self.entry.uuid)
        self.assertEqual(entries[0]["childs"][0]["uuid"], child.uuid)

        # Skip exporting childs
        wiz.include_childs = False
        wiz._onchange_content()
        entries = json.loads(wiz.content)
        self.assertEqual(len(entries), 1)
        self.assertEqual(entries[0]["uuid"], self.entry.uuid)
        self.assertEqual(len(entries[0]["childs"]), 0)
