# Copyright 2017 Therp BV <http://therp.nl>
# Copyright 2021 Camptocamp <https://camptocamp.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# pylint: disable=consider-merging-classes-inherited
from odoo import api, fields, models

REASON_DUPLICATE = "REASON_DUPLICATE"
REASON_DEFAULT = "REASON_DEFAULT"
REASON_DEFAULT_FALSE = "REASON_DEFAULT_FALSE"
REASON_UNKNOWN_MODEL = "REASON_UNKNOWN_MODEL"


class CleanupPurgeLineProperty(models.TransientModel):
    _inherit = "cleanup.purge.line"
    _name = "cleanup.purge.line.property"
    _description = "Cleanup Purge Line Property"

    wizard_id = fields.Many2one(
        "cleanup.purge.wizard.property", "Purge Wizard", readonly=True
    )
    property_id = fields.Many2one("ir.property")
    reason = fields.Selection(
        [
            (REASON_DUPLICATE, "Duplicated property"),
            (REASON_DEFAULT, "Same value as default"),
            (REASON_DEFAULT_FALSE, "Empty default property"),
            (REASON_UNKNOWN_MODEL, "Unknown model"),
        ]
    )

    def purge(self):
        """Delete properties"""
        self.write({"purged": True})
        return self.mapped("property_id").unlink()


class CleanupPurgeWizardProperty(models.TransientModel):
    _inherit = "cleanup.purge.wizard"
    _name = "cleanup.purge.wizard.property"
    _description = "Purge properties"

    @api.model
    def find(self):
        """
        Search property records which are duplicated or the same as the default
        """
        result = []
        default_properties = self.env["ir.property"].search(
            [
                ("res_id", "=", False),
            ]
        )
        handled_field_ids = []
        for prop in default_properties:
            value = None
            try:
                value = prop.get_by_record()
            except KeyError:
                result.append(
                    {
                        "name": "{}@{}: {}".format(prop.name, prop.res_id, value),
                        "property_id": prop.id,
                        "reason": REASON_UNKNOWN_MODEL,
                    }
                )
                continue
            if not value:
                result.append(
                    {
                        "name": "{}@{}: {}".format(prop.name, prop.res_id, value),
                        "property_id": prop.id,
                        "reason": REASON_DEFAULT_FALSE,
                    }
                )
                continue
            if prop.fields_id.id in handled_field_ids:
                continue
            domain = [
                ("id", "!=", prop.id),
                ("fields_id", "=", prop.fields_id.id),
                # =? explicitly tests for None or False, not falsyness
                ("value_float", "=?", prop.value_float or False),
                ("value_integer", "=?", prop.value_integer or False),
                ("value_text", "=?", prop.value_text or False),
                ("value_binary", "=?", prop.value_binary or False),
                ("value_reference", "=?", prop.value_reference or False),
                ("value_datetime", "=?", prop.value_datetime or False),
            ]
            if prop.company_id:
                domain.append(("company_id", "=", prop.company_id.id))
            else:
                domain.extend(
                    [
                        "|",
                        ("company_id", "=", False),
                        (
                            "company_id",
                            "in",
                            self.env["res.company"]
                            .search(
                                [
                                    (
                                        "id",
                                        "not in",
                                        default_properties.filtered(
                                            lambda x: x.company_id
                                            and x.fields_id == prop.fields_id
                                        ).ids,
                                    )
                                ]
                            )
                            .ids,
                        ),
                    ]
                )

            for redundant_property in self.env["ir.property"].search(domain):
                result.append(
                    {
                        "name": "{}@{}: {}".format(
                            prop.name, redundant_property.res_id, prop.get_by_record()
                        ),
                        "property_id": redundant_property.id,
                        "reason": REASON_DEFAULT,
                    }
                )
            handled_field_ids.append(prop.fields_id.id)
        self.env.cr.execute(
            """
            with grouped_properties(ids, cnt) as (
                select array_agg(id), count(*)
                from ir_property group by res_id, company_id, fields_id
            )
            select ids from grouped_properties where cnt > 1
            """
        )
        for (ids,) in self.env.cr.fetchall():
            # odoo uses the first property found by search
            for prop in self.env["ir.property"].search([("id", "in", ids)])[1:]:
                result.append(
                    {
                        "name": "{}@{}: {}".format(
                            prop.name, prop.res_id, prop.get_by_record()
                        ),
                        "property_id": prop.id,
                        "reason": REASON_DUPLICATE,
                    }
                )

        return result

    purge_line_ids = fields.One2many(
        "cleanup.purge.line.property", "wizard_id", "Properties to purge"
    )
