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

import logging
from datetime import datetime, timedelta
from uuid import uuid4

from odoo import _, api, fields, models

_logger = logging.getLogger(__name__)


class VaultInbox(models.Model):
    _name = "vault.inbox"
    _description = _("Vault share incoming secrets")

    token = fields.Char(default=lambda self: uuid4(), readonly=True, copy=False)
    inbox_link = fields.Char(
        compute="_compute_inbox_link",
        readonly=True,
        help="Using this link you can write to the current inbox. If you want people "
        "to create new inboxes you should give them your inbox link from your key "
        "management.",
    )
    user_id = fields.Many2one(
        "res.users",
        "Vault",
        required=True,
    )
    name = fields.Char(required=True)
    secret = fields.Char(readonly=True)
    filename = fields.Char()
    secret_file = fields.Binary(attachment=False, readonly=True)
    key = fields.Char(required=True)
    iv = fields.Char(required=True)
    accesses = fields.Integer(
        "Access counter",
        default=1,
        help="If this is 0 the inbox can't be written using the link",
    )
    expiration = fields.Datetime(
        default=lambda self: datetime.now() + timedelta(days=7),
        help="If expired the inbox can't be written using the link",
    )
    log_ids = fields.One2many("vault.inbox.log", "inbox_id", "Log", readonly=True)

    _sql_constraints = [
        (
            "value_check",
            "CHECK(secret IS NOT NULL OR secret_file IS NOT NULL)",
            _("No value found"),
        ),
    ]

    @api.depends("token")
    def _compute_inbox_link(self):
        base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url")
        for rec in self:
            rec.inbox_link = f"{base_url}/vault/inbox/{rec.token}"

    def read(self, *args, **kwargs):
        # Always load the binary instead of the size
        return super(VaultInbox, self.with_context(bin_size=False)).read(
            *args, **kwargs
        )

    @api.model
    def find_inbox(self, token):
        return self.search([("token", "=", token)])

    def store_in_inbox(
        self,
        name,
        secret,
        secret_file,
        iv,
        key,
        user,
        filename,
        ip=None,
    ):
        log_info = {"name": user.name, "ip": ip or "n/a"}
        if len(self) == 0:
            log = _("Created by %(name)s via %(ip)s") % log_info
            return self.create(
                {
                    "name": name,
                    "accesses": 0,
                    "iv": iv,
                    "key": key,
                    "secret": secret or None,
                    "secret_file": secret_file or None,
                    "filename": filename,
                    "user_id": user.id,
                    "log_ids": [(0, 0, {"name": log})],
                }
            )

        self.ensure_one()
        if self.accesses > 0 and datetime.now() < self.expiration:
            log = _("Written by %(name)s via %(ip)s") % log_info

            self.write(
                {
                    "accesses": self.accesses - 1,
                    "iv": iv,
                    "key": key,
                    "secret": secret or None,
                    "secret_file": secret_file or None,
                    "filename": filename,
                    "log_ids": [(0, 0, {"name": log})],
                }
            )
            return self
