from odoo import models, fields, api, _
import logging

_logger = logging.getLogger(__name__)


class PosOrder(models.Model):
    _inherit = 'pos.order'

    is_online_order = fields.Boolean(
        string='Online Order',
        default=False,
        help='Indicates this order came from the website shop'
    )
    online_order_status = fields.Selection([
        ('pending', 'Pending'),
        ('confirmed', 'Confirmed'),
        ('rejected', 'Rejected'),
    ], string='Online Order Status', default='pending')

    sale_order_id = fields.Many2one(
        'sale.order', string='Source Sale Order',
        help='The website sale order that generated this POS order'
    )
    online_customer_name = fields.Char(
        string='Online Customer',
        compute='_compute_online_customer_name', store=True
    )
    online_order_date = fields.Datetime(
        string='Online Order Date',
        default=fields.Datetime.now
    )
#     delivery_time = fields.Datetime(string='Requested Delivery Time')

    # Note: order_source and fulfilment_type fields are defined in dine360_order_channels
    # dine360_online_orders just uses these fields

    @api.depends('partner_id', 'partner_id.name')
    def _compute_online_customer_name(self):
        for order in self:
            order.online_customer_name = order.partner_id.name or 'Guest'

    def action_confirm_online_order(self):
        """Cashier confirms the online order → sends to KDS and marks as paid if already paid online"""
        self.ensure_one()
        self.write({'online_order_status': 'confirmed'})

        # If it's an online order with an online payment option or Stripe txn, mark as paid in POS to avoid confusion
        has_paid_transaction = False
        if self.sale_order_id:
            has_paid_transaction = any(t.state in ['authorized', 'done'] for t in self.sale_order_id.transaction_ids)

        if self.is_online_order and self.sale_order_id and (self.sale_order_id.payment_option == 'online_gateway' or has_paid_transaction):
            # Check if it needs payment (not yet paid in POS)
            if self.state == 'draft' and self.amount_total > 0 and self.amount_paid < self.amount_total:
                # Find a suitable payment method (Online Payment or Stripe)
                # We prioritize methods linked to the current POS config
                payment_method = self._get_online_payment_method()
                
                if payment_method:
                    _logger.info("Automatically adding online payment from Stripe gateway for order %s using method %s", self.name, payment_method.name)
                    
                    # Use add_payment if it exists, otherwise manual creation
                    payment_data = {
                        'amount': self.amount_total,
                        'payment_date': fields.Datetime.now(),
                        'payment_method_id': payment_method.id,
                        'pos_order_id': self.id,
                    }
                    if hasattr(self, 'add_payment'):
                        self.add_payment(payment_data)
                    else:
                        self.env['pos.payment'].create(payment_data)
                    
                    # Force recomputation of amount_paid
                    self.env.flush_all()
                    self.invalidate_recordset(['payment_ids', 'amount_paid'])
                    
                    # Instead of relying strictly on action_pos_order_paid which throws UserError on cache lag,
                    # we force the state logic directly if we just paid the exact full amount.
                    self.write({'state': 'paid'})
                    try:
                        self._create_order_picking()
                    except AttributeError:
                        _logger.warning("No _create_order_picking method found on POS order")
                    except Exception as e:
                        _logger.error("Error creating picking for online POS order: %s", str(e))
                else:
                    _logger.warning("Could not find a suitable POS Payment Method for online order %s", self.name)

        # Set all order lines to 'waiting' so KDS picks them up
        for line in self.lines:
            if line.product_id.is_kitchen_item and line.product_id.type != 'service':
                line.write({
                    'preparation_status': 'waiting',
                })

        # Notify KDS
        self.lines.filtered(
            lambda l: l.product_id.is_kitchen_item and l.product_id.type != 'service'
        )._notify_kds()

        # Notify POS that order was confirmed
        if self.config_id:
            channel = "online_orders_%s" % self.config_id.id
            self.env['bus.bus']._sendone(channel, 'online_order_confirmed', {
                'order_id': self.id,
                'order_name': self.pos_reference or self.name,
            })

        _logger.info("Online order %s confirmed and sent to KDS", self.name)
        return True

    def action_reject_online_order(self):
        """Cashier rejects the online order"""
        self.ensure_one()
        self.write({'online_order_status': 'rejected'})

        # Notify POS
        if self.config_id:
            channel = "online_orders_%s" % self.config_id.id
            self.env['bus.bus']._sendone(channel, 'online_order_rejected', {
                'order_id': self.id,
                'order_name': self.pos_reference or self.name,
            })

        _logger.info("Online order %s rejected", self.name)
        return True

    @api.model_create_multi
    def create(self, vals_list):
        for vals in vals_list:
            if 'session_id' in vals:
                session = self.env['pos.session'].browse(vals['session_id'])
                if session.config_id.is_kiosk:
                    vals['order_source'] = 'kiosk'
                    vals['fulfilment_type'] = session.config_id.kiosk_service_mode or 'pickup'
        return super().create(vals_list)

    def _get_online_payment_method(self):
        """Find a suitable POS payment method for online/stripe payments"""
        # 1. Look for methods in the current config first
        if self.config_id:
            for method in self.config_id.payment_method_ids:
                if 'online' in method.name.lower() or 'stripe' in method.name.lower():
                    return method
            
            # Fallback to any non-cash method in config
            for method in self.config_id.payment_method_ids:
                if not method.is_cash_count:
                    return method

        # 2. Global search if config search fails
        method = self.env['pos.payment.method'].search([
            ('name', 'ilike', 'Online'),
        ], limit=1)
        if not method:
            method = self.env['pos.payment.method'].search([
                ('name', 'ilike', 'Stripe'),
            ], limit=1)
        if not method:
            method = self.env['pos.payment.method'].search([
                ('is_cash_count', '=', False)
            ], limit=1)
        
        return method

    @api.model
    def get_online_orders(self, config_id):
        """Fetch pending online orders for a specific POS config"""
        domain = [
            ('is_online_order', '=', True),
            ('online_order_status', '=', 'pending'),
            ('config_id', '=', config_id),
        ]
        orders = self.search(domain, order='online_order_date desc')

        result = []
        for order in orders:
            lines = []
            for line in order.lines:
                lines.append({
                    'id': line.id,
                    'product_name': line.full_product_name or line.product_id.name,
                    'qty': line.qty,
                    'price_unit': line.price_unit,
                    'price_subtotal_incl': line.price_subtotal_incl,
                    'customer_note': line.customer_note or '',
                    'is_kitchen_item': line.product_id.is_kitchen_item,
                })

            result.append({
                'id': order.id,
                'name': order.pos_reference or order.name,
                'partner_name': order.partner_id.name or 'Guest',
                'partner_phone': order.partner_id.phone or order.partner_id.mobile or '',
                'amount_total': order.amount_total,
                'date_order': order.date_order.isoformat() if order.date_order else '',
                'sale_order_name': order.sale_order_id.name if order.sale_order_id else '',
                'service_mode': order.fulfilment_type,
                'order_source': order.order_source,
                'note': order.note or '',
                'lines': lines,
            })

        return result
