# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import logging

from odoo import _, api, fields, models

_logger = logging.getLogger(__name__)


class AliasMixin(models.AbstractModel):
    """ A mixin for models that inherits mail.alias. This mixin initializes the
        alias_id column in database, and manages the expected one-to-one
        relation between your model and mail aliases.
    """
    _name = 'mail.alias.mixin'
    _inherits = {'mail.alias': 'alias_id'}
    _description = 'Email Aliases Mixin'
    ALIAS_WRITEABLE_FIELDS = ['alias_name', 'alias_contact', 'alias_defaults', 'alias_bounced_content']

    alias_id = fields.Many2one('mail.alias', string='Alias', ondelete="restrict", required=True)

    # --------------------------------------------------
    # CRUD
    # --------------------------------------------------

    @api.model_create_multi
    def create(self, vals_list):
        """ Create a record with each ``vals`` or ``vals_list`` and create a corresponding alias. """
        # prepare all alias values
        alias_vals_list, record_vals_list = [], []
        for vals in vals_list:
            new_alias = not vals.get('alias_id')
            if new_alias:
                alias_vals, record_vals = self._alias_filter_fields(vals)
                alias_vals.update(self._alias_get_creation_values())
                alias_vals_list.append(alias_vals)
                record_vals_list.append(record_vals)

        # create all aliases
        alias_ids = []
        if alias_vals_list:
            alias_ids = iter(self.env['mail.alias'].sudo().create(alias_vals_list).ids)

        # update alias values in create vals directly
        valid_vals_list = []
        record_vals_iter = iter(record_vals_list)
        for vals in vals_list:
            new_alias = not vals.get('alias_id')
            if new_alias:
                record_vals = next(record_vals_iter)
                record_vals['alias_id'] = next(alias_ids)
                valid_vals_list.append(record_vals)
            else:
                valid_vals_list.append(vals)

        records = super(AliasMixin, self).create(valid_vals_list)

        for record in records:
            record.alias_id.sudo().write(record._alias_get_creation_values())

        return records

    def write(self, vals):
        """ Split writable fields of mail.alias and other fields alias fields will
        write with sudo and the other normally """
        alias_vals, record_vals = self._alias_filter_fields(vals, filters=self.ALIAS_WRITEABLE_FIELDS)
        if record_vals:
            super(AliasMixin, self).write(record_vals)
        if alias_vals and (record_vals or self.check_access_rights('write', raise_exception=False)):
            self.mapped('alias_id').sudo().write(alias_vals)

        return True

    def unlink(self):
        """ Delete the given records, and cascade-delete their corresponding alias. """
        aliases = self.mapped('alias_id')
        res = super(AliasMixin, self).unlink()
        aliases.sudo().unlink()
        return res

    @api.returns(None, lambda value: value[0])
    def copy_data(self, default=None):
        data = super(AliasMixin, self).copy_data(default)[0]
        for fields_not_writable in set(self.env['mail.alias']._fields.keys()) - set(self.ALIAS_WRITEABLE_FIELDS):
            if fields_not_writable in data:
                del data[fields_not_writable]
        return [data]

    def _init_column(self, name):
        """ Create aliases for existing rows. """
        super(AliasMixin, self)._init_column(name)
        if name == 'alias_id':
            # as 'mail.alias' records refer to 'ir.model' records, create
            # aliases after the reflection of models
            self.pool.post_init(self._init_column_alias_id)

    def _init_column_alias_id(self):
        # both self and the alias model must be present in 'ir.model'
        child_ctx = {
            'active_test': False,       # retrieve all records
            'prefetch_fields': False,   # do not prefetch fields on records
        }
        child_model = self.sudo().with_context(child_ctx)

        for record in child_model.search([('alias_id', '=', False)]):
            # create the alias, and link it to the current record
            alias = self.env['mail.alias'].sudo().create(record._alias_get_creation_values())
            record.with_context(mail_notrack=True).alias_id = alias
            _logger.info('Mail alias created for %s %s (id %s)',
                         record._name, record.display_name, record.id)

    # --------------------------------------------------
    # MIXIN TOOL OVERRIDE METHODS
    # --------------------------------------------------

    def _alias_get_creation_values(self):
        """ Return values to create an alias, or to write on the alias after its
            creation.
        """
        return {
            'alias_parent_thread_id': self.id if self.id else False,
            'alias_parent_model_id': self.env['ir.model']._get(self._name).id,
        }

    def _alias_filter_fields(self, values, filters=False):
        """ Split the vals dict into two dictionnary of vals, one for alias
        field and the other for other fields """
        if not filters:
            filters = self.env['mail.alias']._fields.keys()
        alias_values, record_values = {}, {}
        for fname in values.keys():
            if fname in filters:
                alias_values[fname] = values.get(fname)
            else:
                record_values[fname] = values.get(fname)
        return alias_values, record_values
