# -*- coding: utf-8 -*-
import logging
from odoo import api, fields, models, tools, exceptions
import datetime
from dateutil.relativedelta import relativedelta
from werkzeug import urls
import functools
import base64

_logger = logging.getLogger(__name__)

try:
    from jinja2.sandbox import SandboxedEnvironment

    mako_template_env = SandboxedEnvironment(
        block_start_string="<%",
        block_end_string="%>",
        variable_start_string="${",
        variable_end_string="}",
        comment_start_string="<%doc>",
        comment_end_string="</%doc>",
        line_statement_prefix="%",
        line_comment_prefix="##",
        trim_blocks=True,  # do not output newline after blocks
        autoescape=True,  # XML/HTML automatic escaping
    )
    mako_template_env.globals.update({
        'str': str,
        'quote': urls.url_quote,
        'urlencode': urls.url_encode,
        'datetime': datetime,
        'len': len,
        'abs': abs,
        'min': min,
        'max': max,
        'sum': sum,
        'filter': filter,
        'reduce': functools.reduce,
        'map': map,
        'round': round,
        'relativedelta': lambda *a, **kw: relativedelta(*a, **kw),
    })
except ImportError:
    _logger.warning("jinja2 not available, templating features will not work!")
    
class DmsDocumentChoiseTemplate(models.TransientModel):
    _name = 'dms.choise_template'
    _description = 'mklab_dms_document_choise_template'
    
    temp_id = fields.Many2one(comodel_name='dms.template', string='Шаблон', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
    doc_id = fields.Many2one(comodel_name='dms.document', string='Документ')
    company_id = fields.Many2one(comodel_name='res.company', string='Компания', required=True, index=True, default=lambda self: self.env.company)
    
    def get_choise(self):
        for s in self:
            if s.temp_id:
                s.doc_id.text = s.temp_id.text
    
class DmsDocumentTemplate(models.Model):
    _name = 'dms.template'
    _description = 'mklab_dms_document_template'
    
    name = fields.Char(string='Номер', required='1', tracking=True) # Номер — для исходящих с использованием нумератора, для входящих вносится вручную
    text = fields.Html(string='Текст', required='1', tracking=True) # Текст — hmtl
    company_id = fields.Many2one(comodel_name='res.company', string='Компания', required=True, index=True, default=lambda self: self.env.company, tracking=True)

class DmsDocument(models.Model):
    _name = 'dms.document'
    _description = 'Документы'
    _inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin', 'utm.mixin']
    _description = 'mklab_dms_document'
    
    def create_pdf(self):
        report_action = self.env.ref('mklab_dms_document.action_report_dms_document').sudo()
        for s in self:
            if s.type_document=='outgoing':
                pdf, _ = report_action._render_qweb_pdf(report_action.report_name, [s.id])
                s.incoming_file = base64.b64encode(pdf)
                s.incoming_file_type = 'pdf'
            if not s.incoming_file and s.incoming_file_type == 'pdf':
                raise exceptions.UserError('Не указан файл для сохранения')
            if not s.incoming_file_other and s.incoming_file_type != 'pdf':
                raise exceptions.UserError('Не указан файл для сохранения')
            if not s.directory_id:
                raise exceptions.UserError('Не указана директория для сохранения файла')
            content = s.incoming_file if s.incoming_file_type == 'pdf' else s.incoming_file_other
            save_file = self.env['dms.file'].sudo().create({
                'name': s.name,
                'directory_id': s.directory_id.id,
                'content': content,
            })
            s.file = save_file
            s.state = 'done'
    
    def open_choise_template(self):
        company_id = False
        if self.company_id:
            company_id = self.company_id.id
        return {        
            'type': 'ir.actions.act_window', 
            'name': "Выберите шаблон", 
            'res_model': 'dms.choise_template', 
            'target': 'new',
            'view_mode': 'form',
            'context': {'default_doc_id': self.id, 'company_id': company_id}, 
    }

    def unlink(self):
        for s in self:
            if s.state=='done':
                raise exceptions.ValidationError('Нельзя удалить документ, записанный в хранилище')
        res = super().unlink()
        return res
        
    def get_number(self):
        type_document = str(self.env.context.get('default_type_document'))
        if self.type_document:
            type_document = self.type_document
        if type_document == 'incoming':
            self.name = self.env['ir.sequence'].next_by_code('dms.document_number')
            return self.env['ir.sequence'].next_by_code('dms.document_number')
        elif type_document == 'outgoing':
            self.name = self.env['ir.sequence'].next_by_code('dms.document_number_out')
            return self.env['ir.sequence'].next_by_code('dms.document_number_out')
        elif type_document == 'internal':
            self.name = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
            return self.env['ir.sequence'].next_by_code('dms.document_number_internal')
    
    type_document = fields.Selection([('incoming','Входящий документ'),('outgoing','Исходящий документ'),('internal','Внутренний документ')], string='Тип', required="1", tracking=True) # Тип — список выбора (входящее, исходящее, внутреннее)
    name = fields.Char(string='Номер', default=lambda r: r.get_number(), tracking=True) # Номер — для исходящих с использованием нумератора, для входящих вносится вручную
    partner_id = fields.Many2one(comodel_name='res.partner', string='Контакт', required="1", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) # Контакт — от или для кого
    date = fields.Date(string='Дата документа', default=lambda r: datetime.datetime.today(), required="1", tracking=True) # Дата документа
    text = fields.Html(string='Текст') # Текст — hmtl
    incoming_file = fields.Binary(string='Входящий файл (PDF)')
    incoming_file_other = fields.Binary(string='Входящий файл')
    incoming_file_type = fields.Selection([('pdf','PDF'),('other','Другой')], string='Тип входящего файла', default='pdf',tracking=True)
    text_str = fields.Text(string='Текст') # Текст — hmtl
    text_render = fields.Html(string='Текст render') # Текст — hmtl
    file = fields.Many2one(comodel_name='dms.file', string='Связанный файл', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) # Связанный dms.file
    link_model = fields.Many2one(comodel_name='ir.model', string='Связанная модель', tracking=True) # Связанная модель (не обязательно)
    res_id = fields.Integer(string='ID документа в связанной модели', tracking=True) # ID документа в связанной модели (res_id, не обязательно)
    # Эти поля потребуются только для заполнения переменных внутри текста
    print_head = fields.Boolean(string='Печатать шапку', default=False, tracking=True) # Признак печати шапки - булево
    state = fields.Selection([('draft','Черновик'),('done','Записано в хранилище')], string='Статус', default='draft', tracking=True) # Статус — черновик, записано в хранилище
    parent_id = fields.Many2one(comodel_name='dms.document', string='Ссылка на родительский документ', domain="[('id', '!=', id),'|',('partner_id', '=', partner_id),('partner_id.parent_id', '=', partner_id),'|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) #Ссылка на другой (родительский) документ
    child_ids = fields.One2many(comodel_name='dms.document', inverse_name='parent_id', string='Direct subordinates')
    subordinate_ids = fields.One2many(comodel_name='dms.document', string='Subordinates', compute='_compute_subordinates', compute_sudo=True)
    company_id = fields.Many2one(comodel_name='res.company', string='Компания', required=True, index=True, default=lambda self: self.env.company, tracking=True)
    directory_id = fields.Many2one(
        comodel_name="dms.directory",
        string="Директория хранения",
        domain="[('permission_create', '=', True), '|', ('company_id', '=', False), ('company_id', '=', company_id)]",
        context={'dms_directory_show_path': True},
        ondelete="restrict",
        auto_join=True,
        index=True,
        tracking=True
        #domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]"
    )
    
    child_all_count = fields.Integer(string='Indirect Surbordinates Count', compute='_compute_subordinates', store=False, compute_sudo=True)

    def _get_subordinates(self, parents=None):
        if not parents:
            parents = self.env[self._name]

        indirect_subordinates = self.env[self._name]
        parents |= self
        direct_subordinates = self.child_ids - parents
        for child in direct_subordinates:
            child_subordinate = child._get_subordinates(parents=parents)
            indirect_subordinates |= child_subordinate
        return indirect_subordinates | direct_subordinates


    @api.depends('child_ids', 'child_ids.child_all_count')
    def _compute_subordinates(self):
        for doc in self:
            doc.subordinate_ids = doc._get_subordinates()
            doc.child_all_count = len(doc.subordinate_ids)

    
    def render_template(self):
        for s in self:
            template = s.text
            template_new = s.text
            model = s.link_model.model
            res_id = s.res_id
            render_result = 'Не удалось обработать текст'
            substrstart = "${"
            substrend = "}"
            substr_new_start = "<"
            substr_new_end = ">"
            flag = True
            start = 0
            s.text_str = ''
            end = len(template)-1
            while flag:
                try: #search for the item 
                    index = template.index(substrstart,start,end) 
                    start = index+len(substrstart)
                    indexend = template.index(substrend,start,end) 
                    substr = template[index:indexend+1]
                    substr_new_str = substr
                    #s.text_str += str(substr)+ '; '
                    if substr.find(substr_new_start)>0 and substr.find(substr_new_end)>0:
                        new_flag = True
                        start_new = 0
                        end_new = len(substr)-1
                        while new_flag:
                            try: #search for the item 
                                index_new = substr.index(substr_new_start,start_new,end_new) 
                                start_new = index_new+len(substr_new_start)
                                indexend_new = substr.index(substr_new_end,start_new,end_new) 
                                substr_new = substr[index_new:indexend_new+1]
                                #s.text_str += str(index_new) + '-' + str(indexend_new) +':'+str(substr_new)+ '; '
                                substr_new_str = substr_new_str.replace(substr_new,'')
                            except ValueError: 
                                new_flag=False
                        template_new = template_new.replace(substr,substr_new_str)
                except ValueError: 
                    flag = False
            parent = ''
            if s.parent_id:
                type_doc_parent = dict(self._fields['type_document'].selection).get(s.parent_id.type_document)
                parent = ' В ответ на {} {} от {}.'.format(type_doc_parent, s.parent_id.name,s.parent_id.date.strftime('%d.%m.%Y'))
            type_doc = dict(self._fields['type_document'].selection).get(s.type_document)
            s.text_str = '{} {} от {}.{}'.format(type_doc, s.name,s.date.strftime('%d.%m.%Y'), parent)
            template = template_new
            #res = re.findall(r"(${})", template)
            try:
                template = mako_template_env.from_string(tools.ustr(template))
            except:
                template = mako_template_env.from_string(tools.ustr(''))
            user = self.env.user
            variables = {
                'user': user
            }
            if model and res_id:
                record = self.env[model].browse(res_id)
                variables['object'] = record
            
            try:
                render_result = template.render(variables)
            except Exception:
                _logger.error("Failed to render template %r using values %r" % (template, variables))
                render_result = u""
            if render_result == u"False":
                render_result = u""
            s.text_render = render_result
            return render_result
    
    # @api.model
    # def create(self, vals):
    #     if 'name' in vals and 'type_document' in vals:
    #         if vals.get('name', ('New')) == '/' or vals['name'] == '' or vals['name'] == False:
    #             if vals['type_document'] == 'incoming':
    #                 vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number')
    #             if vals['type_document'] == 'outgoing':
    #                 vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_out')
    #             if vals['type_document'] == 'internal':
    #                 vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
    #     for s in self:
    #         if not s.name:
    #             if s.type_document == 'incoming':
    #                 raise  exceptions.ValidationError(self.env['ir.sequence'].next_by_code('dms.document_number'))
    #                 s.name = self.env['ir.sequence'].next_by_code('dms.document_number')
    #             if s.type_document == 'outgoing':
    #                 s.name = self.env['ir.sequence'].next_by_code('dms.document_number_out')
    #             if s.type_document == 'internal':
    #               s.name = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
    #     res = super(mklab_dms_document, self).create(vals)
    #     return res
        
    # def write(self, vals):
    #     if 'name' in vals and 'type_document' in vals:
    #         if vals.get('name', ('New')) == '/' or vals['name'] == '' or vals['name'] == False:
    #             if vals['type_document'] == 'incoming':
    #                 vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number')
    #             if vals['type_document'] == 'outgoing':
    #                 vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_out')
    #             if vals['type_document'] == 'internal':
    #                 vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
    #     if not self.name:
    #         if self.type_document == 'incoming':
    #             raise  exceptions.ValidationError(self.env['ir.sequence'].next_by_code('dms.document_number'))
    #             self.name = self.env['ir.sequence'].next_by_code('dms.document_number')
    #         if self.type_document == 'outgoing':
    #             self.name = self.env['ir.sequence'].next_by_code('dms.document_number_out')
    #         if self.type_document == 'internal':
    #           self.name = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
    #     res = super(mklab_dms_document, self).write(vals)
    #     return res
        
