# Copyright 2015 Florian DA COSTA @ Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from base64 import b64decode
import hashlib
import logging
from odoo import _, api, exceptions, fields, models, registry


_logger = logging.getLogger(__name__)


class IrAttachmentMetadata(models.Model):
    _name = 'ir.attachment.metadata'
    _inherits = {'ir.attachment': 'attachment_id'}
    _inherit = ['mail.thread']

    internal_hash = fields.Char(
        store=True, compute='_compute_hash',
        help="File hash computed with file data to be compared "
             "to external hash when provided.")
    external_hash = fields.Char(
        help="File hash comes from the external owner of the file.\n"
             "If provided allow to check than downloaded file "
             "is the exact copy of the original file.")
    attachment_id = fields.Many2one(
        'ir.attachment', required=True, ondelete='cascade',
        help="Link to ir.attachment model ")
    file_type = fields.Selection(
        selection=[],
        help="The file type determines an import method to be used "
        "to parse and transform data before their import in ERP or an export")
    sync_date = fields.Datetime()
    state = fields.Selection([
        ('pending', 'Pending'),
        ('failed', 'Failed'),
        ('done', 'Done'),
        ], readonly=False, required=True, default='pending')
    state_message = fields.Text()

    @api.depends('datas', 'external_hash')
    def _compute_hash(self):
        for attachment in self:
            if attachment.datas:
                attachment.internal_hash = hashlib.md5(
                    b64decode(attachment.datas)).hexdigest()
            if attachment.external_hash and\
               attachment.internal_hash != attachment.external_hash:
                raise exceptions.UserError(
                    _("File corrupted: Something was wrong with "
                      "the retrieved file, please relaunch the task."))

    @api.model
    def run_attachment_metadata_scheduler(self, domain=None):
        if domain is None:
            domain = [('state', '=', 'pending')]
        batch_limit = self.env.ref(
            'attachment_base_synchronize.attachment_sync_cron_batch_limit') \
            .value
        if batch_limit and batch_limit.isdigit():
            limit = int(batch_limit)
        else:
            limit = 200
        attachments = self.search(domain, limit=limit)
        if attachments:
            return attachments.run()
        return True

    @api.multi
    def run(self):
        """
        Run the process for each attachment metadata
        """
        for attachment in self:
            with api.Environment.manage():
                with registry(self.env.cr.dbname).cursor() as new_cr:
                    new_env = api.Environment(
                        new_cr, self.env.uid, self.env.context)
                    attach = attachment.with_env(new_env)
                    try:
                        attach._run()
                    # pylint: disable=broad-except
                    except Exception as e:
                        attach.env.cr.rollback()
                        _logger.exception(str(e))
                        attach.write({
                            'state': 'failed',
                            'state_message': str(e),
                        })
                        attach.env.cr.commit()
                    else:
                        vals = {
                            'state': 'done',
                            'sync_date': fields.Datetime.now(),
                        }
                        attach.write(vals)
                        attach.env.cr.commit()
        return True

    @api.multi
    def _run(self):
        self.ensure_one()
        _logger.info('Start to process attachment metadata id %d', self.id)

    @api.multi
    def set_done(self):
        """
        Manually set to done
        """
        message = "Manually set to done by %s" % self.env.user.name
        self.write({'state_message': message, 'state': 'done'})
