# -*- encoding: utf-8 -*-
# 项目：JDG-
# 模块名称：
# 描述：
# Copyright 2018 JDG <www.yunside.com>
# Created by wxh (xianhuo.weng@yunside.com) at  2019/8/10 - 5:14 PM

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

_logger = logging.getLogger(__name__)


class SignStatus(models.Model):
    _name = 'jd.digital.signature.status'
    _description = u'电子签名状态'

    res_model = fields.Char(string=u'单据模型名', required=True, help=u'关联的单据模型名')
    order_name = fields.Char(string=u'单据', compute='_get_order_name', store=True)
    res_id = fields.Integer(string=u'单据ID', required=True, help=u'关联的单据ID')
    role_id = fields.Many2one('jd.digital.signature.config.line', string=u'签名角色', required=True)
    signature_img = fields.Binary(string=u'签名图片', attachment=True)
    is_signed = fields.Boolean(string=u'是否已签入单据', default=False)

    domain_role_id = fields.Char(string=u'签名角色domain', compute='_get_domain_role_id')

    @api.multi
    @api.constrains('res_model', 'res_id', 'role_id')
    def check_repeat(self):
        """
        res_model res_id role_id 唯一性校验
        :return:
        """
        for item in self:
            rec = self.sudo().search([
                ('res_model', '=', item.res_model), ('res_id', '=', item.res_id), ('role_id', '=', item.role_id.id),
                ('id', '!=', item.id)])
            if rec:
                order_rec = self.env[item.res_model].sudo().browse(item.res_id)
                raise ValidationError(
                    u'【%s】%s【%s】的签字已存在' % (order_rec._description, order_rec.number, item.role_id.role))

    @api.multi
    @api.depends('role_id')
    def _get_domain_role_id(self):
        for item in self:
            ids = self.env['jd.digital.signature.config.line'].sudo().search([('parent_id.state', '=', True)]).ids
            ids.append(0)
            item.domain_role_id = json.dumps([('id', 'in', ids)])

    @api.multi
    @api.depends('res_model')
    def _get_order_name(self):
        for item in self:
            if item.res_model:
                item.order_name = self.env[item.res_model]._description

    @api.multi
    def get_signature_img_b64(self):
        """
        获取签名图片可直接用于img标签的 base64信息
        :return:
        """
        for item in self:
            # 获取附件信息
            attachment_rec = self.env['ir.attachment'].sudo().search(
                [('res_model', '=', item._name), ('res_id', '=', item.id), ('res_field', '=', 'signature_img')])
            if attachment_rec:
                return 'data:%s;base64,' % attachment_rec.mimetype + attachment_rec.datas

    @api.model
    def get_signature_url_from_role(self, role_id, res_id):
        """
        通过签名角色和单据id获取 签名图片的url
        :param role_id:
        :param res_id:
        :return:
        """
        if type(role_id) == str:
            role_id = int(role_id)
        if type(role_id) == int:
            role_id = self.env['jd.digital.signature.config.line'].browse(role_id)

        res_model = role_id.parent_id.model_id.model
        status_rec = self.env['jd.digital.signature.status'].sudo().search(
            [('res_model', '=', res_model), ('res_id', '=', res_id), ('role_id', '=', role_id.id)],
            order='write_date desc', limit=1)
        if status_rec:
            url_list = self.env['jd.int.attachment'].make_url(res_model='jd.digital.signature.status',
                                                              res_id=status_rec.id,
                                                              res_field='signature_img')
            return url_list and url_list[0]

    @api.model
    def update_status_signed(self, res_model, res_id, is_signed=True):
        """
        更新单据的关联签名图片 为已签
        :param res_model:
        :param res_id:
        :return:
        """
        res_id = int(res_id)
        sign_status_recs = self.sudo().search([('res_model', '=', res_model), ('res_id', '=', res_id)])

        rec = self.env[res_model].sudo().browse(res_id)
        order_range = rec.get_signature_range()
        sign_config_list = self.env['jd.digital.signature.config'].get_signature_config(res_model, order_range)
        for sign_config in sign_config_list:
            sign_status_rec = filter(lambda status_rec: status_rec.role_id.id == sign_config['role_id'],
                                     sign_status_recs)
            sign_status_rec[0].is_signed = is_signed

    @api.model
    def delete_signature(self, res_model, res_id):
        """
        删除单据的 签名图片
        :param res_model:
        :param res_id:
        :return:
        """
        sign_status_recs = self.sudo().search([('res_model', '=', res_model), ('res_id', '=', res_id)])
        sign_status_recs.unlink()

    @api.model
    def get_signature_img_b64_info(self, res_model, res_id):
        """
        获取单据所有的base64 签名图片
        需要带证书的签名图片不允许自动合成
        :param is_exc_certificate: 是否排除带证书签名图片
        :param res_model:
        :param res_id:
        :param use_code:
        :return:
        """
        sign_status_recs = self.sudo().search([('res_model', '=', res_model), ('res_id', '=', res_id)])

        order_range = self.env[res_model].sudo().browse(res_id).get_signature_range()
        # 获取电子签名配置(单据+范围)
        sign_config_list = self.env['jd.digital.signature.config'].get_signature_config(res_model, order_range)

        result = {}
        for sign_config in sign_config_list:
            # 预防一个角色签字多次的问题
            sign_status_recs = filter(lambda status_rec: status_rec.role_id.id == sign_config['role_id'],
                                      sign_status_recs)
            sign_status_recs = sorted(sign_status_recs, key=lambda item: item.write_date, reverse=True)
            # if is_exc_certificate and not sign_config['is_certificate'] and sign_status_rec or \
            #         not is_exc_certificate and sign_status_rec:
            #     sign_status_rec = sign_status_rec[0]
            #     # 不使用url 因为无法做到实时更新
            #     result[sign_config['code']] = sign_status_rec.get_signature_img_b64()
            # else:
            #     result[sign_config['code']] = ''

            if sign_status_recs:
                sign_status_rec = sign_status_recs[0]
                # 如果是带证书的签名 则只有签名成功后才能附加到pdf中
                if sign_config['is_certificate'] and sign_status_rec.is_signed or not sign_config['is_certificate']:
                    result[sign_config['code']] = sign_status_rec.get_signature_img_b64()
            else:
                result[sign_config['code']] = ''
        return result

    @api.model
    def is_signature_upload_finish(self, res_model, res_id):
        is_finish = True
        missing_info = ''
        sign_status_recs = self.sudo().search([('res_model', '=', res_model), ('res_id', '=', res_id)])
        order_range = self.env[res_model].browse(res_id).get_signature_range()
        sign_config_list = self.env['jd.digital.signature.config'].get_signature_config(res_model, order_range)
        for sign_config in sign_config_list:
            sign_status_rec = filter(lambda status_rec: status_rec.role_id.id == sign_config['role_id'],
                                     sign_status_recs)
            if not sign_status_rec:
                is_finish = False
                missing_info += u'缺少签字人员【%s】的签名图片\r\n' % sign_config['role']
        return is_finish, missing_info

    @api.model
    def get_certificate_signature(self, res_model, res_id):
        """
        获取需要带证书的 电子签名图片 以及 身份标识信息
        采用关键字定位
        :param res_model:
        :param res_id:
        :return:
        """
        result = []
        res_id = int(res_id)

        sign_status_recs = self.sudo().search([('res_model', '=', res_model), ('res_id', '=', res_id)])

        order_range = self.env[res_model].sudo().browse(res_id).get_signature_range()
        sign_config_list = self.env['jd.digital.signature.config'].get_signature_config(res_model, order_range)

        order_rec = self.env[res_model].sudo().browse(res_id)
        signature_info = order_rec.get_signature_order_info()
        # 获取身份标识信息
        if 'identification_info' not in signature_info:
            raise ValidationError(u'无法获取单据【%s】%s身份认证信息' % (order_rec._description, order_rec.number))
        for sign_config in sign_config_list:
            if sign_config['is_certificate']:
                sign_status_rec = filter(lambda status_rec: status_rec.role_id.id == sign_config['role_id'],
                                         sign_status_recs)
                if sign_status_rec:
                    # 查找对应签名图片附件
                    attachment_rec = self.env['ir.attachment'].sudo().search(
                        [('res_model', '=', self._name), ('res_field', '=', 'signature_img'),
                         ('res_id', '=', sign_status_rec[0].id)])
                    file_name = u'【%s】签字' % sign_config['role']

                    # 获取身份标识信息
                    identification_info = signature_info['identification_info']
                    if sign_config['code'] not in identification_info:
                        raise ValidationError(u'无法获取单据【%s】%s -【%s】身份认证信息' % (
                            order_rec._description, order_rec.number, sign_config['role']))

                    mime_map = {
                        'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
                        'application/vnd.ms-word': 'doc',
                        'application/vnd.ms-excel': 'xls',
                        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
                        'application/vnd.ms-powerpoint': 'ppt',
                        'application/pdf': 'pdf',
                        'application/zip': 'zip',
                        'application/x-rar': 'rar',
                        'text/plain': 'txt',
                        'image/jpeg': 'jpeg',
                        'image/jpg': 'jpg',
                        'image/x-ms-bmp': 'bmp',
                        'image/png': 'png',
                        'audio/mpeg': 'mp3',
                        'video/x-msvideo': 'avi',
                        'video/mp4': 'mp4',
                        'video/x-ms-wmv': 'wn',
                        'video/x-matroska': 'mkv',
                        "application/x-pdf": 'pdf'
                    }

                    result.append({
                        'identification': identification_info[sign_config['code']],
                        'keyword': sign_config['role'],
                        # 'file_name': file_name + mimetypes.guess_extension(attachment_rec.mimetype),
                        'file_name': file_name + '.' + mime_map[attachment_rec.mimetype],
                        'file_data': attachment_rec.datas,
                        # 'extension': mimetypes.guess_extension(attachment_rec.mimetype)[1:]
                        'extension': mime_map[attachment_rec.mimetype],
                    })

        return result
