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

import logging
from uuid import uuid4

from odoo import _, api, fields, models

_logger = logging.getLogger(__name__)


class Vault(models.Model):
    _name = "vault"
    _description = _("Vault")
    _inherit = ["vault.abstract"]
    _order = "name"

    user_id = fields.Many2one(
        "res.users",
        "Owner",
        readonly=True,
        default=lambda self: self.env.user,
        required=True,
    )
    right_ids = fields.One2many(
        "vault.right",
        "vault_id",
        "Rights",
        default=lambda self: self._get_default_rights(),
    )
    entry_ids = fields.One2many("vault.entry", "vault_id", "Entries")
    field_ids = fields.One2many("vault.field", "vault_id", "Fields")
    file_ids = fields.One2many("vault.file", "vault_id", "Files")
    log_ids = fields.One2many("vault.log", "vault_id", "Log", readonly=True)
    reencrypt_required = fields.Boolean(default=False)

    # Access control
    perm_user = fields.Many2one("res.users", compute="_compute_access", store=False)
    allowed_read = fields.Boolean(compute="_compute_access", store=False)
    allowed_create = fields.Boolean(compute="_compute_access", store=False)
    allowed_share = fields.Boolean(compute="_compute_access", store=False)
    allowed_write = fields.Boolean(compute="_compute_access", store=False)
    allowed_delete = fields.Boolean(compute="_compute_access", store=False)

    master_key = fields.Char(
        compute="_compute_master_key",
        inverse="_inverse_master_key",
        store=False,
    )

    uuid = fields.Char(default=lambda self: uuid4(), required=True, readonly=True)
    name = fields.Char(required=True)
    note = fields.Text()

    _sql_constraints = [
        ("uuid_uniq", "UNIQUE(uuid)", _("The UUID must be unique.")),
    ]

    @api.depends("right_ids.user_id")
    def _compute_access(self):
        user = self.env.user
        for rec in self.sudo():
            rec.perm_user = user.id

            if user == rec.user_id:
                rec.write(
                    {
                        "allowed_create": True,
                        "allowed_share": True,
                        "allowed_write": True,
                        "allowed_delete": True,
                        "allowed_read": True,
                    }
                )
                continue

            rights = rec.right_ids
            rec.allowed_read = user in rights.mapped("user_id")
            rec.allowed_create = user in rights.filtered("perm_create").mapped(
                "user_id"
            )
            rec.allowed_share = user in rights.filtered("perm_share").mapped("user_id")
            rec.allowed_write = user in rights.filtered("perm_write").mapped("user_id")
            rec.allowed_delete = user in rights.filtered("perm_delete").mapped(
                "user_id"
            )

    @api.depends("right_ids.key")
    def _compute_master_key(self):
        domain = [("user_id", "=", self.env.uid)]
        for rec in self:
            rights = rec.right_ids.filtered_domain(domain)
            rec.master_key = rights[0].key if rights else False

    def _inverse_master_key(self):
        domain = [("user_id", "=", self.env.uid)]
        for rec in self:
            rights = rec.right_ids.filtered_domain(domain)
            if rights and not rights.key:
                rights.key = rec.master_key

    def _get_default_rights(self):
        return [
            (
                0,
                0,
                {
                    "user_id": self.env.uid,
                    "perm_create": True,
                    "perm_write": True,
                    "perm_delete": True,
                    "perm_share": True,
                },
            )
        ]

    def _log_entry(self, msg, state):
        self.ensure_one()
        return (
            self.env["vault.log"]
            .sudo()
            .create(
                {
                    "vault_id": self.id,
                    "user_id": self.env.uid,
                    "message": msg,
                    "state": state,
                }
            )
        )

    def share_public_keys(self):
        self.ensure_one()
        result = []
        for right in self.right_ids:
            result.append({"user": right.user_id.id, "public": right.public_key})
        return result

    def action_open_import_wizard(self):
        self.ensure_one()
        wizard = self.env.ref("vault.view_vault_import_wizard")
        return {
            "name": _("Import from file"),
            "type": "ir.actions.act_window",
            "view_mode": "form",
            "res_model": "vault.import.wizard",
            "views": [(wizard.id, "form")],
            "view_id": wizard.id,
            "target": "new",
            "context": {"default_vault_id": self.id},
        }

    def action_open_export_wizard(self):
        self.ensure_one()
        wizard = self.env.ref("vault.view_vault_export_wizard")
        return {
            "name": _("Export to file"),
            "type": "ir.actions.act_window",
            "view_mode": "form",
            "res_model": "vault.export.wizard",
            "views": [(wizard.id, "form")],
            "view_id": wizard.id,
            "target": "new",
            "context": {"default_vault_id": self.id},
        }
