# -*- coding: utf-8 -*-
# Copyright 2018 JDG <www.yunside.com>
# Created by summerrain <summerrain5445@gmail.com> at 2018/8/1

from odoo import fields, api, models
import json
from odoo.exceptions import ValidationError, AccessError
import logging

_logger = logging.getLogger(__name__)

TYPE_TERMINAL = [('app', 'APP'), ('pc', 'PC'), ('all', u'所有')]


class AccessSecurity(models.Model):
    _name = 'jd.access.security.extra'
    _inherit = 'jdg.abstract.base.data.m'
    _description = u'权限增强配置'
    _order = 'id desc'

    company_id = fields.Many2one('res.company', default=False)
    name = fields.Char(required=False)

    model_id = fields.Many2one('ir.model', string=u'业务单据', required=True, index=True)
    type_terminal = fields.Selection(TYPE_TERMINAL, string=u'终端类型', required=True, index=True)

    type_ids = fields.Many2many('jd.department.type',
                                'jd_access_security_department_type',
                                'security_id',
                                'type_id',
                                string=u'角色组类型', required=True)

    perm_read = fields.Boolean(string=u'查看', default=True)
    perm_write = fields.Boolean(string=u'编辑', default=False)
    perm_create = fields.Boolean(string=u'创建', default=False)
    perm_unlink = fields.Boolean(string=u'删除', default=False)

    domain_model_id = fields.Char(string=u'单据类型domain', compute='_get_domain_model_id')

    @api.multi
    @api.depends('model_id')
    def _get_domain_model_id(self):
        for item in self:
            base_biz_class = self.env['jdg.abstract.base.biz'].__class__
            ids = [0]
            model_recs = self.env['ir.model'].sudo().search(
                [('model', 'not like', 'ir.'), ('model', 'not like', 'wizard.')])
            for rec in model_recs:
                if rec.model in self.env and issubclass(self.env[rec.model].__class__, base_biz_class):
                    ids.append(rec.id)
            item.domain_model_id = json.dumps([('id', 'in', ids)])
            
    @api.multi
    @api.depends('state')
    def get_hide_edit_button(self):
        for item in self:
            item.hide_edit_button = item.state in ('enable', 'discard')

    @api.model
    def create(self, values):
        """
        获取自动编号
        :param values:
        :return:
        """
        if values.get('number', '/') == '/':
            values.update({
                'number': self.env['ir.sequence'].next_by_code(self._name)
            })
        return super(AccessSecurity, self).create(values)

    @api.multi
    @api.depends('model_id')
    def name_get(self):
        """
        名称显示格式：[XXX]YYY
        """
        result = []
        for item in self:
            company_name = u'通用' if not item.company_id else item.company_id.name
            name = u'【%s】(%s)' % (self.env[item.model_id.model]._description, company_name)
            result.append((item.id, name))
        return result

    @api.multi
    def verify_data(self):
        for item in self:
            # 是否存在已启用的数据
            rec = self.sudo().search(
                [('state', '=', 'enable'), ('model_id', '=', item.model_id.id),
                 ('type_terminal', '=', item.type_terminal),
                 ('company_id', '=', item.company_id.id)])
            if rec:
                model_name = self.env[item.model_id.model]._description
                terminal_name = dict(self._fields['type_terminal'].selection).get(item.type_terminal)
                company_name = u'通用' if not item.company_id else item.company_id.name
                raise ValidationError(u'存在已启用的【%s-%s】(%s)记录，请检查' %
                                      (model_name, terminal_name, company_name))

    @api.multi
    def do_enable(self):
        for item in self:
            item.verify_data()
        self.clear_caches()
        return super(AccessSecurity, self).do_enable()
    
    @api.multi
    def do_disable(self):
        self.clear_caches()
        return super(AccessSecurity, self).do_disable()
    
    @api.model
    def check(self, model, mode, type_terminal, raise_exception=True):
        """
        检查是否有某个单据的访问权限
        :param model:
        :param mode:
        :param type_terminal:
        :return: None不作限制,后续odoo权限校验 True权限校验通过 False权限校验不通过
        """
        # 暂不对审核、反审核做限制
        if mode in ('audit', 'unaudit'):
            return None

        type_list = self.env['jd.department.type'].get_type_list() or ['-1']
        cr = self.env.cr
        # 是否存在启用的限制
        
        sql = '''
            SELECT
                jas.perm_create,
                jas.perm_read,
                jas.perm_write,
                jas.perm_unlink
            FROM jd_access_security_extra jas
                LEFT JOIN ir_model m ON jas.model_id = m.id
                LEFT JOIN jd_access_security_department_type ref_type ON jas.id = ref_type.security_id
                LEFT JOIN jd_department_type type ON ref_type.type_id = type.id
            WHERE m.model = %(model)s
                  AND (jas.type_terminal = %(type_terminal)s OR jas.type_terminal = 'all')
                  AND jas.state = 'enable'
                  AND (jas.company_id ISNULL OR jas.company_id = %(company_id)s)
                  AND type.number IN %(type_list)s
            ORDER BY jas.company_id ASC, jas.type_terminal = 'all' ASC
            LIMIT 1
        '''
        cr.execute(sql, {
            'model': model,
            'type_terminal': type_terminal,
            'company_id': self.env.user.company_id.id,
            'type_list': tuple(type_list),
        })

        perm_result = cr.dictfetchone()
        if not perm_result:
            return None
        else:
            is_perm = perm_result.get('perm_' + mode, None)
            if not is_perm and raise_exception:
                model_desc = self.env[model]._description if self.env[model]._description else model
                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
                }
                # 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)
                # msg = '%s %s' % (msg_heads[mode], msg_tail)
                msg = msg_heads[mode]
                raise AccessError(msg)
            return is_perm
        
    @api.model
    def get_app_auth(self):
        type_list = self.env['jd.department.type'].get_type_list() or ['-1']
        cr = self.env.cr
        company_id = self.env.user.company_id.id
        sql = '''
            SELECT
                DISTINCT ON (jas.model_id)
                m.model,
                jas.perm_write,
                jas.perm_delete,
                jas.perm_create,
                jas.perm_read
            FROM jd_access_security_extra jas
            LEFT JOIN ir_model m ON jas.model_id = m.id
            LEFT JOIN jd_access_security_department_type ref ON ref.security_id = jas.id
            LEFT JOIN jd_department_type dt ON ref.type_id = dt.id
            WHERE jas.state = 'enable'
                  AND (jas.company_id = %(company_id)s OR jas.company_id ISNULL)
                  AND jas.type_terminal IN ('app', 'all')
                  AND dt.number in %(type_list)s
            ORDER BY jas.model_id, jas.company_id ASC, jas.type_terminal = 'all' ASC
        '''
        cr.execute(sql, {'company_id': company_id, 'type_list': tuple(type_list)})
        result = cr.dictfetchall()
        return result
