# -*- coding: utf-8 -*-
# greburs by InteGreat

from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.osv import expression


class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'
    
    production_ids = fields.One2many('mrp.production', 'sale_line_id', string='Produccion')
    purchase_request_line_ids = fields.One2many('purchase.request.line', 'sale_line_id', string='Compra')
    order_line_replenishment_id = fields.Many2one('sale.order.line.replenishment', copy=False)

    @api.model_create_multi
    def create(self, vals_list):
        lines = super().create(vals_list)
        for line in lines:
            if line.qty_delivered_method == 'stock_move' and not line.order_line_replenishment_id:
                route = self.env['stock.location.route'].search([('sale_selectable', '=', True)], limit=1)
                self.env['sale.order.line.replenishment'].create({'order_line_id': line.id, 'route_id': route.id})
        return lines

    def _prepare_procurement_group_vals(self):
        res = super()._prepare_procurement_group_vals()
        res['sale_order_ids'] = [(4, self.order_id.id)]
        return res


class SaleOrder(models.Model):
    _inherit = "sale.order"

    order_replenishment_ids = fields.One2many('sale.order.line.replenishment', 'order_id')
    to_be_replenished = fields.Char(compute='_compute_order_replenishment_status')
    purchase_request_line_count = fields.Integer('Solicitudes de compra', compute='_compute_purchase_request_count')

    @api.depends('order_replenishment_ids.qty_open_demand', 'delivery_status')
    def _compute_order_replenishment_status(self):
        for order in self:
            order.to_be_replenished = 'no'
            if not order._origin.id:
            # new order not saved: yes
                order.to_be_replenished = 'new'
            for line in order.order_replenishment_ids:
                if (line.qty_open_demand > 0 or line.qty_to_order > 0) and order.delivery_status != 'done':
                    order.to_be_replenished = 'yes'

    def action_run_order_replenishment(self):
        for order in self:
            for line in order.order_replenishment_ids:
                line.action_replenish_line()
            order.action_confirm()

    # OVERRIDE: replenishment production ids added to mto logic
    @api.depends('procurement_group_id.stock_move_ids.created_production_id.procurement_group_id.mrp_production_ids',
                 'order_line.production_ids')
    def _compute_mrp_production_count(self):
        super(SaleOrder, self)._compute_mrp_production_count()
        for sale in self:
            sale.mrp_production_count += len(sale.order_line.production_ids)

    # override + replenishment production ids added to mto logic
    def action_view_mrp_production(self):
        self.ensure_one()
        mrp_production_ids = \
            self.procurement_group_id.stock_move_ids.created_production_id.procurement_group_id.mrp_production_ids.ids \
            + self.order_line.production_ids.ids
        action = {
            'res_model': 'mrp.production',
            'type': 'ir.actions.act_window',
        }
        if len(mrp_production_ids) == 1:
            action.update({
                'view_mode': 'form',
                'res_id': mrp_production_ids[0],
            })
        else:
            action.update({
                'name': _("Manufacturing Orders Generated by %s", self.name),
                'domain': [('id', 'in', mrp_production_ids)],
                'view_mode': 'tree,form',
            })
        return action

    @api.depends('order_line.purchase_request_line_ids')
    def _compute_purchase_request_count(self):
        for sale in self:
            sale.purchase_request_line_count = len(sale.order_line.purchase_request_line_ids)

    def action_view_purchase_request(self):
        self.ensure_one()
        purchase_request_ids = self.order_line.purchase_request_line_ids.ids
        action = {
            'name': _("Solicitudes de compra generadas por %s", self.name),
            'res_model': 'purchase.request.line',
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', purchase_request_ids)],
            'view_mode': 'tree,form',
        }
        return action

    # override completely in order to don't loop twice
    def name_get(self):
        res = []
        if self._context.get('sale_show_partner_name'):
            partner = True
        else:
            partner = False
        for order in self:
            name = order.name
            if order.client_order_ref:
                name = '%s (%s)' % (name, order.client_order_ref)
            if partner:
                name = '%s - %s' % (name, order.partner_id.name)
            res.append((order.id, name))
        return res

    # override completely
    # we do not care about search by partner name even if in the context:'sale_show_partner_name'
    @api.model
    def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
        if operator == 'ilike' and not (name or '').strip():
            domain = []
        elif operator in ('ilike', 'like', '=', '=like', '=ilike'):
            domain = expression.AND([
                args or [],
                ['|', ('name', operator, name), ('client_order_ref', operator, name)]
            ])
            return self._search(domain, limit=limit, access_rights_uid=name_get_uid)


class SaleOrderLineReplenishment(models.Model):
    _name = 'sale.order.line.replenishment'
    _description = 'Order Line Replenishment Extension'
    _inherits = {'sale.order.line': 'order_line_id'}

    order_line_id = fields.Many2one('sale.order.line', auto_join=True, index=True, required=True, ondelete="cascade")
    qty_free_product = fields.Float(compute='_compute_data', digits='Product Unit of Measure', compute_sudo=True)
    qty_open_demand = fields.Float(string='Open', digits='Product Unit of Measure', compute='_compute_data', store=True)
    qty_planned = fields.Float(string='Planned', digits='Product Unit of Measure', compute='_compute_data', compute_sudo=True)
    location_dest_id = fields.Many2one('stock.location', string='Location', compute='onchange_procurement_action', compute_sudo=True)
    procurement_action = fields.Selection([('manufacture', 'Producir'), ('buy', 'Comprar')], string='Acción',
        default='manufacture', required=True)
    qty_to_order = fields.Float('Otra cantidad', digits='Product Unit of Measure', default=0.0)
    replenishment_route_id = fields.Many2one('stock.location.route', string='Route',
        compute='onchange_procurement_action', store=True)

    @api.depends('procurement_action', 'order_id.warehouse_id')
    def onchange_procurement_action(self):
        for line in self:
            rule = self.env['stock.rule'].search([
                ('action', '=', line.procurement_action), ('warehouse_id', '=', line.order_id.warehouse_id.id)
            ], limit=1)
            if rule:
                line.replenishment_route_id = rule.route_id
                line.location_dest_id = rule.location_id
            else:
                line.replenishment_route_id = False
                line.location_dest_id = False

    @api.depends('qty_to_deliver', 'production_ids.product_qty', 'purchase_request_line_ids.product_qty')
    def _compute_data(self):
        for line in self:
            # qtys
            line.qty_open_demand = 0
            line.qty_planned = 0
            line.qty_free_product = 0
            if line.qty_to_deliver > 0.0:
                # qtys
                qty = 0.0
                line.qty_free_product = \
                    line.product_id.with_context(location=line.order_id.warehouse_id.lot_stock_id.id).free_qty
                for production in line.production_ids:
                    if production.state != 'cancel':
                        qty += production.product_qty
                for request in line.purchase_request_line_ids:
                    if not request.cancelled:
                        qty += request.product_qty
                line.qty_planned = qty
                line.qty_open_demand = line.qty_to_deliver - line.qty_free_product - line.qty_reserved_delivery - qty

    def action_replenish_line(self):
        procurements = []
        for line in self:
            if line.qty_to_order > 0:
                product_qty = line.qty_to_order
            elif line.qty_open_demand > 0:
                product_qty = line.qty_open_demand
            else:
                continue
            line_uom = line.product_uom
            quant_uom = line.product_id.uom_id

            product_qty, procurement_uom = line_uom._adjust_uom_quantities(product_qty, quant_uom)

            group_id = line._prepare_replenishment_procurement_group()
            date_planned = line.order_id.commitment_date
            values = {
                'group_id': group_id,
                'sale_line_id': line.order_line_id.id,
                'date_planned': date_planned,
                'route_ids': line.replenishment_route_id,
                'product_description_variants': line.order_line_id._get_sale_order_line_multiline_description_variants(),
                'company_id': line.order_id.company_id,
            }

            procurements.append(self.env['procurement.group'].Procurement(
                line.product_id, product_qty, procurement_uom, line.location_dest_id,
                line.name, line.order_id.name, line.order_id.company_id, values))
            line.qty_to_order = 0
        if procurements:
            self.env['procurement.group'].run(procurements)

    def _prepare_replenishment_procurement_group(self):
        action = self.replenishment_route_id.rule_ids[0].action
        if action == 'manufacture':
            name = 'P-%s-%s-' % (self.order_id.name, str(self.sequence))
            counted = len(self.production_ids)
        else:
            name = 'C-%s-%s-' % (self.order_id.name, str(self.sequence))
            counted = len(self.purchase_request_line_ids)
        return self.env['procurement.group'].create({
            'name': name + str(counted + 1),
            'move_type': self.order_id.picking_policy,
            'sale_order_ids': [(4, self.order_id.id)],
        })
