# -*- coding:utf-8 -*-
# 项目: jdg-core-base
# Copyright 2018 JDG <www.yunside.com>
# Created by bjccdsrlcr (longjie.jiang@yunside.com) @ 2018/10/8
import logging
from odoo import api, fields, models, SUPERUSER_ID, tools,  _
from odoo.exceptions import AccessError, UserError, ValidationError
from ....jd_init.model.jdg_sudo.base_suspend_security import BaseSuspendSecurityUid
_logger = logging.getLogger(__name__)

MODE_LIST = ('read', 'write', 'create', 'unlink', 'audit', 'unaudit', 'export')


class IrModelAccessInherit(models.Model):
    _inherit = 'ir.model.access'
    _description = u'模型访问权限'

    perm_read = fields.Boolean(string=u'读')
    perm_write = fields.Boolean(string=u'写')
    perm_create = fields.Boolean(string=u'创建')
    perm_unlink = fields.Boolean(string=u'删除')
    perm_audit = fields.Boolean(string=u'审核/启用')
    perm_unaudit = fields.Boolean(string=u'反审核/停用')
    perm_export = fields.Boolean(string=u'导出')


    @api.model
    def check_group(self, model, mode, group_ids):
        # 增加审核、反审核
        assert mode in MODE_LIST, 'Invalid access mode'
        
        if isinstance(model, models.BaseModel):
            assert model._name == 'ir.model', 'Invalid model object'
            model_name = model.name
        else:
            model_name = model

        if isinstance(group_ids, (int, long)):
            group_ids = [group_ids]

        query = """ SELECT 1 FROM ir_model_access a
                    JOIN ir_model m ON (m.id = a.model_id)
                    WHERE a.active AND a.perm_{mode} AND
                        m.model=%s AND (a.group_id IN %s OR a.group_id IS NULL)
                """.format(mode=mode)
        self._cr.execute(query, (model_name, tuple(group_ids)))
        return bool(self._cr.rowcount)

    @api.model_cr
    def group_names_with_access(self, model_name, access_mode):
        """ Return the names of visible groups which have been granted
            ``access_mode`` on the model ``model_name``.
           :rtype: list
        """
        # assert access_mode in ('read', 'write', 'create', 'unlink'), 'Invalid access mode'
        # 增加审核、反审核
        assert access_mode in MODE_LIST, 'Invalid access mode'
        self._cr.execute("""SELECT c.name, g.name
                            FROM ir_model_access a
                                JOIN ir_model m ON (a.model_id=m.id)
                                JOIN res_groups g ON (a.group_id=g.id)
                                LEFT JOIN ir_module_category c ON (c.id=g.category_id)
                            WHERE m.model=%s AND a.active IS TRUE AND a.perm_""" + access_mode,
                         (model_name,))
        return [('%s/%s' % x) if x[0] else x[1] for x in self._cr.fetchall()]

    # The context parameter is useful when the method translates error messages.
    # But as the method raises an exception in that case,  the key 'lang' might
    # not be really necessary as a cache key, unless the `ormcache_context`
    # decorator catches the exception (it does not at the moment.)
    @api.model
    @tools.ormcache_context('self._uid', 'model', 'mode', 'raise_exception', keys=('lang',))
    def check(self, model, mode='read', raise_exception=True):
        if self._uid == 1:
            # User root have all accesses
            return True
        if self.env.context.get('force_user_with_admin') == self._uid:
            return True
        if isinstance(self._uid, BaseSuspendSecurityUid):
            return True
        
        # assert mode in ('read', 'write', 'create', 'unlink'), 'Invalid access mode'
        # 增加审核、反审核
        assert mode in MODE_LIST, 'Invalid access mode'
        
        type_terminal = 'app' if self.env.context.get('source_type', 0) == 1 else 'pc'
        is_pass = self.env['jd.access.security.extra'].check(model, mode, type_terminal, raise_exception)
        if is_pass is not None:
            return is_pass

        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

        # We check if a specific rule exists
        self._cr.execute("""SELECT MAX(CASE WHEN perm_{mode} THEN 1 ELSE 0 END)
                              FROM ir_model_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
                               AND a.active IS TRUE""".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 ir_model_access a
                                  JOIN ir_model m ON (m.id = a.model_id)
                                 WHERE a.group_id IS NULL
                                   AND m.model = %s
                                   AND a.active IS TRUE""".format(mode=mode),
                             (model_name,))
            r = self._cr.fetchone()[0]

        if not r and raise_exception:
            # 获取可访问的组的组名
            # groups = '\n\t'.join('- %s' % g for g in self.group_names_with_access(model_name, mode))
            model_desc = self.env[model_name]._description if self.env[model_name]._description else model_name
            msg_heads = {
                # Messages are declared in extenso so they are properly exported in translation terms
                'read': u"错误，您没有查看%s的权限" % model_desc,
                'write':  u"错误，您没有编辑%s的权限" % model_desc,
                'create': u"错误，您没有创建%s的权限" % model_desc,
                'unlink': u"错误，您没有删除%s的权限" % model_desc,
                'audit': u'错误，您没有审核%s的权限' % model_desc,
                'unaudit': u'错误，您没有反审核%s的权限' % model_desc,
                'export': u'错误，您没有%s的导出权限' % model_desc
            }
            # if groups:
            #     msg_tail = u"单据名" + ": %s"
            #     msg_params = (model._description if model._description else 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)
            msg = msg_heads[mode]
            raise AccessError(msg)

        return bool(r)