# -*- coding:utf-8 -*-
# 项目: jdg-core-base
# Copyright 2018 JDG <www.yunside.com>
# Created by bjccdsrlcr (longjie.jiang@yunside.com) @ 2018/12/3

from odoo import models, fields, api, tools
import logging
from odoo.exceptions import AccessError
from ....jd_init.model.jdg_sudo.base_suspend_security import BaseSuspendSecurityUid

_logger = logging.getLogger(__name__)


class JdButtonAccess(models.Model):
    _name = 'jd.button.access'
    _description = u'按钮访问控制'
    """
    控制按钮访问
    """

    group_id = fields.Many2one('res.groups', string=u'所属群组', ondelete='cascade')
    model_id = fields.Many2one('ir.model', string=u'模型', required=True, domain=[('transient', '=', False)], index=True, ondelete='cascade')
    perm_confirm = fields.Boolean(string=u'确认权限', default=True, help=u'该群组对于该菜单是否有确认权限')
    perm_cancel = fields.Boolean(string=u'作废权限', default=False, help=u'该群组对于该菜单是否有作废权限')
    special_button_ids = fields.Many2many('jd.button', 
                                          'jd_base_jd_button_access_jd_button', 
                                          'access_id', 
                                          'button_id',
                                          string=u'特殊按钮访问控制')

    @api.model
    def group_names_with_access(self, model_name, operation):
        """ Return the names of visible groups which have been granted
            ``access_mode`` on the model ``model_name``.
           :rtype: list
        """
        sql = """
        SELECT re.number, re.group_name FROM (SELECT jb.number as number, rg.name as group_name
                       FROM jd_button_access a
                       JOIN jd_base_jd_button_access_jd_button ab ON a.id = ab.access_id
                       JOIN jd_button jb ON jb.id = ab.button_id
                       JOIN ir_model m ON (m.id = a.model_id)
                       JOIN res_groups rg ON a.group_id = rg.id
                       WHERE m.model = %s
                       AND jb.number = %s) re
        """
        self.env.cr.execute(sql, (model_name, operation))
        rs = self._cr.fetchall()
        return [('%s/%s' % x) if x[0] else x[1] for x in rs]

    @api.model
    @tools.ormcache_context('self._uid', 'model', 'mode', 'raise_exception', keys=('lang',))
    def check(self, model, mode='confirm', raise_exception=True):
        if self._uid == 1:
            # User root have all accesses
            return True
        if isinstance(self._uid, BaseSuspendSecurityUid):
            return True
        button_map = self.env['jd.button'].get_button_map()
        # if isinstance(self._uid, BaseSuspendSecurityUid):
        #     return True
        if isinstance(model, models.BaseModel):
            assert model._name == 'ir.model', 'Invalid model object'
            model_name = model.model
        else:
            model_name = model

        # TransientModel records have no access rights, only an implicit access rule
        if model_name not in self.env:
            _logger.error('Missing model %s', model_name)
        elif self.env[model_name].is_transient():
            return True
        if mode in ('confirm', 'cancel'):
            # We check if a specific rule exists
            self._cr.execute("""SELECT MAX(CASE WHEN perm_{mode} THEN 1 ELSE 0 END)
                                  FROM jd_button_access a
                                  JOIN ir_model m ON (m.id = a.model_id)
                                  JOIN res_groups_users_rel gu ON (gu.gid = a.group_id)
                                 WHERE m.model = %s
                                   AND gu.uid = %s""".format(mode=mode),
                             (model_name, self._uid,))
            r = self._cr.fetchone()[0]
            if not r:
                # there is no specific rule. We check the generic rule
                self._cr.execute("""SELECT MAX(CASE WHEN perm_{mode} THEN 1 ELSE 0 END)
                                      FROM jd_button_access a
                                      JOIN ir_model m ON (m.id = a.model_id)
                                     WHERE a.group_id IS NULL
                                       AND m.model = %s""".format(mode=mode),
                                 (model_name,))
                r = self._cr.fetchone()[0]

            if not r and raise_exception:
                msg_heads = {
                    'confirm': u"你没有确认该单据的权限",
                    'cancel':  u"你没有取消该单据的权限",
                }
                msg_tail = u"没有找到允许访问该单据的权限配置，请联系你的系统管理员" + "\n\n" + u"模型名" + ": %s"
                msg_params = (model_name,)
                _logger.info('Access Denied by ACLs for operation: %s, uid: %s, model: %s', mode, self._uid, model_name)
                msg = '%s %s' % (msg_heads[mode], msg_tail)
                raise AccessError(msg % msg_params)

            return bool(r)
        else:
            has_group_sql = """
                    SELECT re.number FROM (SELECT jb.number
                                                              FROM jd_button_access a
                                                              JOIN jd_base_jd_button_access_jd_button ab ON a.id = ab.access_id
                                                              JOIN jd_button jb ON jb.id = ab.button_id
                                                              JOIN ir_model m ON (m.id = a.model_id)
                                                              JOIN res_groups_users_rel gu ON (gu.gid = a.group_id)
                                                              WHERE m.model = %s
                                                              AND gu.uid = %s) re
            """
            self.env.cr.execute(has_group_sql, (model_name, self._uid))
            r = self._cr.fetchone()
            if not r:
                no_group_sql = """
                SELECT re.number FROM (SELECT jb.number
                                       FROM jd_button_access a
                                       JOIN jd_base_jd_button_access_jd_button ab ON a.id = ab.access_id
                                       JOIN jd_button jb ON jb.id = ab.button_id
                                       JOIN ir_model m ON (m.id = a.model_id)
                                       JOIN res_groups_users_rel gu ON (gu.gid = a.group_id)
                                       WHERE a.group_id IS NULL
                                       AND m.model = %s) re
                """
                self.env.cr.execute(no_group_sql, (model_name,))
                r = self._cr.fetchone()
            if not r and raise_exception:
                # 获取可访问的组的组名
                groups = '\n\t'.join('- %s' % g for g in self.group_names_with_access(model_name, mode))
                msg_heads = {
                    mode: u"你没有该单据%s的权限" % button_map[mode],
                }
                if groups:
                    msg_tail = u"模型名" + ": %s"
                    msg_params = (model_name,)
                else:
                    msg_tail = u"没有找到允许访问该单据的权限配置，请联系你的系统管理员" + "\n\n" + u"模型名" + ": %s"
                    msg_params = (model_name,)
                _logger.info('Access Denied by ACLs for operation: %s, uid: %s, model: %s', mode, self._uid, model_name)
                msg = '%s %s' % (msg_heads[mode], msg_tail)
                raise AccessError(msg % msg_params)
            return bool(r)