from datetime import timedelta

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


class LaundryOrderUnlockWizard(models.TransientModel):
    """Manager-only wizard that grants a TIMED unlock window on a
    locked laundry.order.

    The wizard does not unlock the order permanently — it sets
    `manager_unlocked_until` to a future timestamp. The lock compute
    on `laundry.order.locked` re-evaluates against `now()` on every
    read, so once the window passes the order auto-relocks. No manual
    re-lock action is needed; nothing can drift.

    Audit trail:
      - reason is logged as a chatter note via mail.message
      - manager_unlocked_by stores the actor
      - manager_unlock_reason stores the rationale on the order itself
    """
    _name = 'laundry.order.unlock.wizard'
    _description = 'Unlock Laundry Order for Editing'

    DEFAULT_DURATION = 30  # minutes
    MAX_DURATION = 240     # minutes (4 hours)

    order_id = fields.Many2one(
        'laundry.order', string='Order',
        required=True, readonly=True, ondelete='cascade',
    )
    order_name = fields.Char(
        related='order_id.name', readonly=True,
    )
    order_source_type = fields.Selection(
        related='order_id.source_type', readonly=True,
    )
    order_state = fields.Selection(
        related='order_id.state', readonly=True,
    )
    duration_minutes = fields.Integer(
        string='Unlock For (minutes)',
        default=DEFAULT_DURATION,
        required=True,
        help='How long the order will accept edits before re-locking '
             'automatically. Capped at %s minutes.' % MAX_DURATION,
    )
    reason = fields.Char(
        string='Reason',
        required=True,
        help='Logged in the chatter for audit. Required.',
    )

    @api.constrains('duration_minutes')
    def _check_duration(self):
        for wiz in self:
            if wiz.duration_minutes < 1:
                raise UserError(_('Unlock duration must be at least 1 minute.'))
            if wiz.duration_minutes > self.MAX_DURATION:
                raise UserError(_(
                    'Unlock duration is capped at %s minutes.',
                    self.MAX_DURATION,
                ))

    def action_unlock(self):
        self.ensure_one()
        if not self.env.user.has_group(
            'laundry_management.group_laundry_manager_override'
        ):
            raise AccessError(_(
                'Only users with the "Laundry / Manager Override" '
                'privilege can unlock locked orders.'
            ))
        if not self.reason or not self.reason.strip():
            raise UserError(_('A reason is required to unlock an order.'))

        unlock_until = (
            fields.Datetime.now() + timedelta(minutes=self.duration_minutes)
        )
        # The wizard writes only manager_unlocked_* fields, which are NOT
        # in LOCKED_HEADER_FIELDS — the lock guard is a no-op for this
        # write, so we don't need a context bypass.
        self.order_id.sudo().write({
            'manager_unlocked_until': unlock_until,
            'manager_unlocked_by': self.env.user.id,
            'manager_unlock_reason': self.reason.strip(),
        })
        self.order_id.message_post(
            body=_(
                'Order unlocked for %(minutes)s minutes by '
                '<strong>%(user)s</strong>. Re-locks automatically at '
                '%(until)s.<br/><strong>Reason:</strong> %(reason)s',
                minutes=self.duration_minutes,
                user=self.env.user.name,
                until=fields.Datetime.to_string(unlock_until),
                reason=self.reason.strip(),
            ),
            subtype_xmlid='mail.mt_note',
        )
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'laundry.order',
            'res_id': self.order_id.id,
            'view_mode': 'form',
            'target': 'current',
        }

    def action_relock_now(self):
        """Optional: managers can also re-lock immediately (clears the
        unlock window early). Same access control as unlock."""
        self.ensure_one()
        if not self.env.user.has_group(
            'laundry_management.group_laundry_manager_override'
        ):
            raise AccessError(_('Only override managers can re-lock.'))
        self.order_id.sudo().write({
            'manager_unlocked_until': False,
        })
        self.order_id.message_post(
            body=_(
                'Order re-locked early by <strong>%(user)s</strong>.',
                user=self.env.user.name,
            ),
            subtype_xmlid='mail.mt_note',
        )
        return {'type': 'ir.actions.act_window_close'}
