# © 2021 Hibou Corp.

from io import BytesIO
from base64 import b64encode, b64decode
from json import loads, dumps

from odoo import models, fields, api
from odoo.addons.queue_job.job import job
from odoo.addons.component.core import Component
from odoo.addons.queue_job.exception import RetryableJobError

FEED_RETRY_PATTERN = {
    1:  1 * 60,
    5:  2 * 60,
    10: 10 * 60,
}


class AmazonFeed(models.Model):
    _name = 'amazon.feed'
    _description = 'Amazon Feed'
    _order = 'id desc'
    _rec_name = 'external_id'

    backend_id = fields.Many2one('amazon.backend', string='Backend')
    external_id = fields.Char(string='Amazon Feed ID')
    type = fields.Selection([
        ('POST_ORDER_FULFILLMENT_DATA', 'Order Fulfillment Data'),
        ('POST_PRODUCT_DATA', 'Product Data'),
        ('POST_INVENTORY_AVAILABILITY_DATA', 'Product Inventory'),
        ('POST_PRODUCT_PRICING_DATA', 'Product Pricing'),
    ], string='Feed Type')
    content_type = fields.Selection([
        ('text/xml', 'XML'),
    ], string='Content Type')
    data = fields.Binary(string='Data', attachment=True)
    response = fields.Binary(string='Response', attachment=True)
    state = fields.Selection([
        ('new', 'New'),
        ('submitted', 'Submitted'),
        ('error_on_submit', 'Submission Error'),
    ], string='State', default='new')
    amazon_state = fields.Selection([
        ('not_sent', ''),
        ('invalid', 'Invalid'),
        ('UNCONFIRMED', 'Request Pending'),
        ('SUBMITTED', 'Submitted'),
        ('IN_SAFETY_NET', 'Safety Net'),
        ('IN_QUEUE', 'Queued'),
        ('IN_PROGRESS', 'Processing'),
        ('DONE', 'Done'),
        ('CANCELLED', 'Cancelled'),
        ('AWAITING_ASYNCHRONOUS_REPLY', 'Awaiting Asynchronous Reply'),
    ], default='not_sent')
    amazon_stock_picking_id = fields.Many2one('amazon.stock.picking',
                                              string='Shipment',
                                              ondelete='set null')
    amazon_product_product_id = fields.Many2one('amazon.product.product',
                                                string='Listing',
                                                ondelete='set null')

    @api.multi
    @job(default_channel='root.amazon')
    def submit_feed(self):
        for feed in self:
            api_instance = feed.backend_id.get_wrapped_api()
            feeds_api = api_instance.feeds()
            feed_io = BytesIO(b64decode(feed.data))
            res1, res2 = feeds_api.submit_feed(feed.type, feed_io, content_type=feed.content_type)
            feed_id = res2.payload.get('feedId')
            if not feed_id:
                if res2.payload:
                    feed.response = b64encode(dumps(res2.payload))
                feed.state = 'error_on_submit'
            else:
                feed.state = 'submitted'
                feed.external_id = feed_id
                # First attempt will be delayed 1 minute
                # Next 5 retries will be delayed 10 min each
                # The rest will be delayed 30 min each
                feed.with_delay(priority=100).check_feed()

    @api.multi
    @job(default_channel='root.amazon', retry_pattern=FEED_RETRY_PATTERN)
    def check_feed(self):
        for feed in self.filtered('external_id'):
            api_instance = feed.backend_id.get_wrapped_api()
            feeds_api = api_instance.feeds()
            res3 = feeds_api.get_feed(feed.external_id)
            status = res3.payload['processingStatus']
            try:
                feed.amazon_state = status
            except ValueError:
                feed.amazon_state = 'invalid'
            if status in ('IN_QUEUE', 'IN_PROGRESS'):
                raise RetryableJobError('Check back later on: ' + str(status), ignore_retry=True)
            if status in ('DONE', ):
                feed_document_id = res3.payload['resultFeedDocumentId']
                if feed_document_id:
                    response = feeds_api.get_feed_result_document(feed_document_id)
                    try:
                        feed.response = b64encode(response)
                    except TypeError:
                        feed.response = b64encode(response.encode())

                    # queue a job to process the response
                    feed.with_delay(priority=10).process_feed_result()

    @job(default_channel='root.amazon')
    def process_feed_result(self):
        for feed in self:
            pass
