# Copyright 2017-2020 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
"""Define tab that can be added to partner form, for a selection of relations."""
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError

from ..tablib import Tab


class ResPartnerTab(models.Model):
    """Model that defines relation types that might exist between partners"""

    _name = "res.partner.tab"
    _description = "Tabs to add to partner"
    _order = "name"

    @api.model
    def get_partner_types(self):
        """Partner types are defined by model res.partner.relation.type."""
        # pylint: disable=no-self-use
        rprt_model = self.env["res.partner.relation.type"]
        return rprt_model.get_partner_types()

    code = fields.Char(
        string="Code", required=True, help="Language independent code for tab"
    )
    name = fields.Char(
        string="Name",
        required=True,
        index=True,
        translate=True,
        help="Will provide title for tab in user language",
    )
    contact_type = fields.Selection(
        selection="get_partner_types", string="Valid for partner type"
    )
    partner_category_id = fields.Many2one(
        comodel_name="res.partner.category", string="Valid for partner category"
    )
    partner_ids = fields.Many2many(
        comodel_name="res.partner",
        string="Partners with this tab",
        help="This tab will only show for certain partners.\n"
        "Do not combine this with selection for contact type or"
        " category.",
    )

    @api.constrains("contact_type", "partner_category_id", "partner_ids")
    def _check_partner_ids(self):
        """If partner_ids filled, other domain fields should be empty."""
        if self.partner_ids and (self.contact_type or self.partner_category_id):
            raise ValidationError(
                _("You can not both specify partner_ids and other criteria.")
            )

    @api.multi
    def update_types(self, vals=None):
        """Update types on write or unlink.

        If we have no vals, assume unlink.
        """
        if vals:
            contact_type = vals.get("contact_type", False)
            partner_category_id = vals.get("partner_category_id", False)
        type_model = self.env["res.partner.relation.type"]
        for this in self:
            for tab_side in ("left", "right"):
                side_tab = "tab_%s_id" % tab_side
                relation_types = type_model.search([(side_tab, "=", this.id)])
                for relation_type in relation_types:
                    type_value = relation_type["contact_type_%s" % tab_side]
                    category_value = relation_type["partner_category_%s" % tab_side]
                    tab_invalid_for_type = (
                        not vals  # When called from unlink
                        or (contact_type and contact_type != type_value)
                        or (
                            partner_category_id
                            and partner_category_id != category_value.id
                        )
                    )
                    if tab_invalid_for_type:
                        relation_type.write({side_tab: False})

    @api.model
    def create(self, vals):
        """Create new tab."""
        result = super().create(vals)
        self._update_modification_sequence()
        return result

    @api.multi
    def write(self, vals):
        """Remove tab from types no longer satifying criteria."""
        if vals.get("contact_type", False) or vals.get("partner_category_id", False):
            self.update_types(vals)
        result = super().write(vals)
        self._update_modification_sequence()
        return result

    @api.multi
    def unlink(self):
        """Unlink should first remove references."""
        self.update_types()
        result = super().unlink()
        self._update_modification_sequence()
        return result

    def _update_modification_sequence(self):
        """Update sequence used to check change in tab definitions."""
        sequence_model = self.env["res.partner.tab.sequence"]
        sequence_model.increment_sequence()

    @api.model
    def get_tabs(self):
        """Convert information on tabs in database to array of objects."""
        tabs = [Tab(tab_record) for tab_record in self.search([])]
        return tabs
