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

from odoo import api, fields, models, _
from odoo.exceptions import ValidationError


class MailActivityPLanTemplate(models.Model):
    _inherit = 'mail.activity.plan.template'

    responsible_type = fields.Selection(selection_add=[
        ('coach', 'Coach'),
        ('manager', 'Manager'),
        ('employee', 'Employee'),
    ], ondelete={'coach': 'cascade', 'manager': 'cascade', 'employee': 'cascade'})

    @api.constrains('plan_id', 'responsible_type')
    def _check_responsible_hr(self):
        """ Ensure that hr types are used only on employee model """
        for template in self.filtered(lambda tpl: tpl.plan_id.res_model != 'hr.employee'):
            if template.responsible_type in {'coach', 'manager', 'employee'}:
                raise ValidationError(_('Those responsible types are limited to Employee plans.'))

    def _get_closest_parent_user(self, employee, responsible, error_message):
        responsible_parent = responsible
        viewed_responsible = [employee]
        while True:
            if not responsible_parent:
                return {
                    'error': error_message,
                    'responsible': False
                }
            if responsible_parent.user_id:
                return {
                    'error': False,
                    'responsible': responsible_parent.user_id
                }
            if responsible_parent in viewed_responsible:
                return {
                    "error": _(
                        "Oops! It seems there is a problem with your team structure.\
                        We found a circular reporting loop and no one in that loop is linked to a user.\
                        Please double-check that everyone reports to the correct manager."
                    ),
                    "responsible": False,
                }
            else:
                viewed_responsible.append(responsible_parent)
                responsible_parent = responsible_parent.parent_id

    def _determine_responsible(self, on_demand_responsible, employee):
        if self.plan_id.res_model != 'hr.employee' or self.responsible_type not in {'coach', 'manager', 'employee'}:
            return super()._determine_responsible(on_demand_responsible, employee)
        result = {"error": "", "responsible": False}
        if self.responsible_type == 'coach':
            if not employee.coach_id:
                result['error'] = _('Coach of employee %s is not set.', employee.name)
            result['responsible'] = employee.coach_id.user_id
            if employee.coach_id and not result['responsible']:
                # If a plan cannot be launched due to the coach not being linked to an user,
                # attempt to assign it to the coach's manager user. If that manager is also not linked
                # to an user, continue searching upwards until a manager with a linked user is found.
                result = self._get_closest_parent_user(
                    employee=employee,
                    responsible=employee.coach_id.parent_id,
                    error_message=_(
                        "The user of %s's coach is not set.", employee.name
                    ),
                )

        elif self.responsible_type == 'manager':
            if not employee.parent_id:
                result['error'] = _('Manager of employee %s is not set.', employee.name)
            result['responsible'] = employee.parent_id.user_id
            if employee.parent_id and not result['responsible']:
                # If a plan cannot be launched due to the manager not being linked to an user,
                # attempt to assign it to the manager's manager user. If that manager is also not linked
                # to an user, continue searching upwards until a manager with a linked user is found.
                result = self._get_closest_parent_user(
                    employee=employee,
                    responsible=employee.parent_id.parent_id,
                    error_message=_(
                        "The manager of %s should be linked to a user.", employee.name
                    ),
                )

        elif self.responsible_type == 'employee':
            result['responsible'] = employee.user_id
            if not result['responsible']:
                # If a plan cannot be launched due to the employee not being linked to an user,
                # attempt to assign it to the manager's user. If the manager is also not linked
                # to an user, continue searching upwards until a manager with a linked user is found.
                result = self._get_closest_parent_user(
                    employee=employee,
                    responsible=employee.parent_id,
                    error_message=_(
                        "The employee %s should be linked to a user.", employee.name
                    ),
                )

        if result['error'] or result['responsible']:
            return result
