import logging

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

_logger = logging.getLogger(__name__)


class RentalReturnWizard(models.TransientModel):
    _name = 'rental.return.wizard'
    _description = 'Rental Return & Inspection'

    order_id = fields.Many2one(
        'sale.order',
        string="Rental Order",
        required=True,
        readonly=True,
    )
    partner_id = fields.Many2one(related='order_id.partner_id')
    currency_id = fields.Many2one(related='order_id.currency_id')

    line_ids = fields.One2many(
        'rental.return.wizard.line',
        'wizard_id',
        string="Items to Return",
        readonly=True,
    )

    inspection_condition = fields.Selection(
        [
            ('good', 'Good - No Issues'),
            ('fair', 'Fair - Minor Wear'),
            ('damaged', 'Damaged'),
        ],
        string="Product Condition",
        required=True,
    )
    inspection_notes = fields.Text(
        string="Inspection Notes",
        help="Describe the condition of the returned items.",
    )
    inspection_photo_ids = fields.Many2many(
        'ir.attachment',
        'rental_return_wizard_photo_rel',
        'wizard_id',
        'attachment_id',
        string="Inspection Photos",
    )

    @api.model
    def default_get(self, fields_list):
        res = super().default_get(fields_list)
        order_id = res.get('order_id') or self.env.context.get('default_order_id')
        if not order_id:
            return res

        order = self.env['sale.order'].browse(order_id)
        precision = self.env['decimal.precision'].precision_get('Product Unit')

        lines_vals = []
        for line in order.order_line.filtered(
            lambda r: r.is_rental
            and r.product_type != 'combo'
            and float_compare(
                r.qty_delivered, r.qty_returned,
                precision_digits=precision,
            ) > 0
        ):
            lines_vals.append((0, 0, {
                'sale_line_id': line.id,
                'product_id': line.product_id.id,
                'description': line.name,
                'qty_delivered': line.qty_delivered,
                'qty_returned': line.qty_returned,
                'qty_to_return': line.qty_delivered - line.qty_returned,
            }))

        if not lines_vals:
            raise UserError(_(
                "No items are available for return. Either nothing has been "
                "delivered or all items have already been returned."
            ))

        res['line_ids'] = lines_vals
        return res

    def action_confirm(self):
        """Validate inspection, apply results, and process the return."""
        self.ensure_one()
        order = self.order_id

        if not order._has_completed_delivery():
            raise UserError(_(
                "Cannot process return: no delivery has been completed "
                "for this order."
            ))

        if not self.inspection_photo_ids:
            raise UserError(_(
                "Inspection photos are required. Please attach at least one "
                "photo showing the condition of the returned items."
            ))

        if self.inspection_condition in ('fair', 'damaged') and not self.inspection_notes:
            raise UserError(_(
                "Please provide inspection notes describing the issue "
                "when condition is '%s'.",
                dict(self._fields['inspection_condition'].selection).get(
                    self.inspection_condition, self.inspection_condition,
                ),
            ))

        self._apply_inspection(order)
        self._process_return(order)

        return {'type': 'ir.actions.act_window_close'}

    def _apply_inspection(self, order):
        """Write inspection results to the sale order."""
        if self.inspection_condition == 'good':
            status = 'passed'
        else:
            status = 'flagged'

        order.write({
            'rental_inspection_status': status,
            'rental_inspection_notes': self.inspection_notes or '',
            'rental_inspection_photo_ids': [(6, 0, self.inspection_photo_ids.ids)],
        })

        if status == 'passed':
            order.message_post(body=_(
                "Return inspection completed: condition is good. "
                "Security deposit refund process initiated."
            ))
            if order.rental_deposit_status == 'collected':
                order._refund_security_deposit()
        else:
            condition_label = dict(
                self._fields['inspection_condition'].selection,
            ).get(self.inspection_condition, self.inspection_condition)

            order.message_post(body=_(
                "Return inspection completed: condition is '%s'. "
                "Flagged for review.\nNotes: %s",
                condition_label,
                self.inspection_notes or '-',
            ))

            order.activity_schedule(
                'mail.mail_activity_data_todo',
                date_deadline=fields.Date.today(),
                summary=_("Return inspection flagged - %s", order.name),
                note=_(
                    "Returned items from %s inspected as '%s'. "
                    "Review the inspection photos and process the deposit.\n"
                    "Notes: %s",
                    order.partner_id.name,
                    condition_label,
                    self.inspection_notes or '-',
                ),
                user_id=order.user_id.id or self.env.uid,
            )
            order._send_damage_notification_email()

    def _process_return(self, order):
        """Mark items as returned via stock picking or rental wizard."""
        picking = order.picking_ids.filtered(
            lambda p: p.state == 'assigned'
            and p.picking_type_code == 'incoming'
        )

        if picking:
            picking = picking[:1]
            for move in picking.move_ids.filtered(
                lambda m: m.state not in ('done', 'cancel')
            ):
                if move.product_uom.is_zero(move.quantity):
                    move.quantity = move.product_uom_qty
            try:
                picking.with_context(
                    skip_sanity_check=False,
                    cancel_backorder=True,
                ).button_validate()
            except Exception as e:
                _logger.error(
                    "Auto-validate return picking %s for %s failed: %s",
                    picking.name, order.name, e,
                )
                raise UserError(_(
                    "Could not automatically process the return picking. "
                    "Please validate the return picking manually.\n\n"
                    "Inspection has been saved successfully.\n\n"
                    "Error: %s", str(e),
                )) from e
            return

        precision = self.env['decimal.precision'].precision_get(
            'Product Unit',
        )
        for line in self.line_ids:
            sol = line.sale_line_id
            if float_compare(
                sol.qty_delivered, sol.qty_returned,
                precision_digits=precision,
            ) > 0:
                sol.qty_returned = sol.qty_delivered


class RentalReturnWizardLine(models.TransientModel):
    _name = 'rental.return.wizard.line'
    _description = 'Rental Return Wizard Line'

    wizard_id = fields.Many2one(
        'rental.return.wizard',
        required=True,
        ondelete='cascade',
    )
    sale_line_id = fields.Many2one(
        'sale.order.line',
        string="Order Line",
        readonly=True,
    )
    product_id = fields.Many2one(
        'product.product',
        string="Product",
        readonly=True,
    )
    description = fields.Char(readonly=True)
    qty_delivered = fields.Float(
        string="Qty Delivered",
        readonly=True,
    )
    qty_returned = fields.Float(
        string="Already Returned",
        readonly=True,
    )
    qty_to_return = fields.Float(
        string="Qty to Return",
        readonly=True,
    )
