# -*- coding: utf-8 -*-

from odoo import models, fields, api, _
from odoo.exceptions import UserError


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

    custom_purchase_count = fields.Integer(
        string='Purchase',
        compute='_compute_custom_purchase_count'
    )

    def _compute_custom_purchase_count(self):
        for so in self:
            po_count = self.env['purchase.order'].search_count([
                ('sale_ord_id', '=', so.id)
            ])
            so.custom_purchase_count = po_count

    def action_view_custom_purchase(self):
        """Open the list of purchase orders linked to this sale order"""
        purchases = self.env['purchase.order'].search([
            ('sale_ord_id', '=', self.id)
        ])
        return {
            'name': _('Purchase Order'),
            'view_mode': 'list,form',
            'res_model': 'purchase.order',
            'domain': [('id', 'in', purchases.ids)],
            'type': 'ir.actions.act_window',
        }


class PurchaseOrder(models.Model):
    _inherit = 'purchase.order'

    sale_ord_id = fields.Many2one(
        'sale.order',
        string='Sale Order',
        readonly=True,
        help='The sale order from which this purchase order was created'
    )
    
    marked_for = fields.Char(
        string='Marked For',
        readonly=True,
        help='The customer/person this purchase order is marked for (from Sales Order)'
    )
    
    custom_sale_count = fields.Integer(
        string='Sales',
        compute='_compute_custom_sale_count'
    )

    def _compute_custom_sale_count(self):
        for po in self:
            if po.sale_ord_id:
                po.custom_sale_count = 1
            else:
                po.custom_sale_count = 0

    def action_view_linked_sale_order(self):
        """Open the linked sale order"""
        self.ensure_one()
        if not self.sale_ord_id:
            raise UserError(_("No Sale Order is linked to this Purchase Order."))
        return {
            'name': _('Sale Order'),
            'view_mode': 'form',
            'res_model': 'sale.order',
            'res_id': self.sale_ord_id.id,
            'type': 'ir.actions.act_window',
        }

    def _open_match_wizard(self, search_hint=''):
        """Open the match sale order wizard for manual selection"""
        wizard = self.env['match.sale.order.wiz'].create({
            'purchase_order_id': self.id,
            'search_hint': search_hint,
        })
        return {
            'name': _('Match Sale Order'),
            'type': 'ir.actions.act_window',
            'res_model': 'match.sale.order.wiz',
            'res_id': wizard.id,
            'view_mode': 'form',
            'target': 'new',
        }

    def action_match_sale_order(self):
        """
        Match this PO to a Sale Order based on x_marked_for field.
        If no match or multiple matches, opens a wizard for manual selection.
        """
        self.ensure_one()
        import re
        
        if self.sale_ord_id:
            raise UserError(_("This Purchase Order is already linked to Sale Order: %s") % self.sale_ord_id.name)
        
        # Get the x_marked_for value
        marked_for_value = getattr(self, 'x_marked_for', None)
        
        # If no x_marked_for, open wizard directly for manual selection
        if not marked_for_value:
            return self._open_match_wizard('')
        
        matching_partners = None
        marked_for_str = str(marked_for_value)
        search_hint = marked_for_str
        
        # Check if x_marked_for contains a partner ID reference like "res.partner(11519,)"
        partner_id_match = re.search(r'res\.partner\((\d+)', marked_for_str)
        if partner_id_match:
            partner_id = int(partner_id_match.group(1))
            partner = self.env['res.partner'].browse(partner_id).exists()
            if partner:
                matching_partners = partner
                search_hint = partner.name  # Use actual name for search hint
        
        # If not a partner ID reference, search by name
        if not matching_partners:
            matching_partners = self.env['res.partner'].search([
                '|',
                ('name', 'ilike', marked_for_str),
                ('display_name', 'ilike', marked_for_str)
            ])
        
        # If no matching partners found, open wizard for manual selection
        if not matching_partners:
            return self._open_match_wizard(search_hint)
        
        # Find Sale Orders for these partners
        matching_sales = self.env['sale.order'].search([
            ('partner_id', 'in', matching_partners.ids)
        ])
        
        # If no Sale Orders found, open wizard for manual selection
        if not matching_sales:
            return self._open_match_wizard(matching_partners[0].name if matching_partners else search_hint)
        
        # If multiple Sale Orders, open wizard for manual selection
        if len(matching_sales) > 1:
            return self._open_match_wizard(matching_partners[0].name if matching_partners else search_hint)
        
        # Exactly one match - link it automatically
        customer_name = matching_partners[0].name
        self.write({
            'sale_ord_id': matching_sales.id,
            'marked_for': customer_name,
        })
        
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'title': _('Success'),
                'message': _('Linked to Sale Order: %s') % matching_sales.name,
                'type': 'success',
                'sticky': False,
            }
        }

    def action_batch_match_sale_orders(self):
        """
        Batch match multiple POs to Sale Orders based on x_marked_for field.
        Called from list view action.
        """
        import re
        matched = 0
        skipped = 0
        errors = []
        
        for po in self:
            if po.sale_ord_id:
                skipped += 1
                continue
            
            marked_for_value = getattr(po, 'x_marked_for', None)
            if not marked_for_value:
                skipped += 1
                continue
            
            marked_for_str = str(marked_for_value)
            matching_partners = None
            
            # Check if x_marked_for contains a partner ID reference
            partner_id_match = re.search(r'res\.partner\((\d+)', marked_for_str)
            if partner_id_match:
                partner_id = int(partner_id_match.group(1))
                matching_partners = self.env['res.partner'].browse(partner_id).exists()
            
            # If not a partner ID reference, search by name
            if not matching_partners:
                matching_partners = self.env['res.partner'].search([
                    '|',
                    ('name', 'ilike', marked_for_str),
                    ('display_name', 'ilike', marked_for_str)
                ])
            
            if not matching_partners:
                errors.append(_("PO %s: No customer found for '%s'") % (po.name, marked_for_str))
                continue
            
            # Find Sale Orders for these partners
            matching_sales = self.env['sale.order'].search([
                ('partner_id', 'in', matching_partners.ids)
            ])
            
            if not matching_sales:
                errors.append(_("PO %s: No SO found for '%s'") % (po.name, matching_partners[0].name))
                continue
            
            if len(matching_sales) > 1:
                errors.append(_("PO %s: Multiple SOs (%d) for '%s'") % (po.name, len(matching_sales), matching_partners[0].name))
                continue
            
            # Exactly one match - link it with actual customer name
            customer_name = matching_partners[0].name
            po.write({
                'sale_ord_id': matching_sales.id,
                'marked_for': customer_name,
            })
            matched += 1
        
        message = _("Matched: %d, Skipped: %d") % (matched, skipped)
        if errors:
            message += "\n" + "\n".join(errors[:5])  # Show first 5 errors
            if len(errors) > 5:
                message += _("\n... and %d more errors") % (len(errors) - 5)
        
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'title': _('Batch Match Complete'),
                'message': message,
                'type': 'info' if matched > 0 else 'warning',
                'sticky': True,
            }
        }