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

HR_OFFICER_GROUP = "hr_holidays.group_hr_holidays_user"

_XENO_UNIT_MAP = {
    "full_day": "day",
    "part_time": "hour",
    "first_half": "half_day",
    "second_half": "half_day",
}


class XenoLeaveHrUpdate(models.TransientModel):
    _name = "xeno.leave.hr.update"
    _description = "HR Update: edit a submitted leave application"

    leave_id = fields.Many2one("hr.leave", required=True)
    employee_id = fields.Many2one(related="leave_id.employee_id", readonly=True)
    holiday_status_id = fields.Many2one("hr.leave.type", string="Time Off Type", required=True)
    request_date_from = fields.Date(string="Start Date", required=True)
    request_date_to = fields.Date(string="End Date", required=True)
    request_hour_from = fields.Float(string="From")
    request_hour_to = fields.Float(string="To")
    reason = fields.Text(
        string="Reason for change", required=True,
        help="Recorded on the leave's chatter for audit purposes.")

    # Same content-editing UI as the Apply-for-Leave form (balance strip +
    # Leave Type Basis pills) so HR edits a leave with the same context an
    # employee sees applying for one -- deliberately NOT the approval
    # chain, which this wizard has no business touching.
    xeno_flexible_duration = fields.Boolean(
        related="holiday_status_id.xeno_flexible_duration", readonly=True)
    xeno_request_unit = fields.Selection(
        [
            ("full_day", "Full-day Leave"),
            ("part_time", "Part-time Leave"),
            ("first_half", "First-half Day Leave"),
            ("second_half", "Second-half Day Leave"),
        ],
        string="Leave Type Basis", default="full_day")

    xeno_balance_total = fields.Float(compute="_compute_xeno_balance", digits=(16, 2))
    xeno_balance_used = fields.Float(compute="_compute_xeno_balance", digits=(16, 2))
    xeno_balance_pending = fields.Float(compute="_compute_xeno_balance", digits=(16, 2))
    xeno_balance_remaining = fields.Float(compute="_compute_xeno_balance", digits=(16, 2))

    @api.depends("employee_id", "holiday_status_id")
    def _compute_xeno_balance(self):
        Leave = self.env["hr.leave"].sudo()
        Alloc = self.env["hr.leave.allocation"].sudo()
        for wizard in self:
            emp_id = wizard.employee_id.id
            lt_id = wizard.holiday_status_id.id
            if not emp_id or not lt_id:
                wizard.xeno_balance_total = 0.0
                wizard.xeno_balance_used = 0.0
                wizard.xeno_balance_pending = 0.0
                wizard.xeno_balance_remaining = 0.0
                continue
            total = sum(Alloc.search([
                ("employee_id", "=", emp_id),
                ("holiday_status_id", "=", lt_id),
                ("state", "=", "validate"),
            ]).mapped("number_of_days"))
            used = sum(Leave.search([
                ("employee_id", "=", emp_id),
                ("holiday_status_id", "=", lt_id),
                ("state", "=", "validate"),
            ]).mapped("number_of_days"))
            pending = sum(Leave.search([
                ("employee_id", "=", emp_id),
                ("holiday_status_id", "=", lt_id),
                ("state", "in", ["confirm", "validate1"]),
            ]).mapped("number_of_days"))
            wizard.xeno_balance_total = total
            wizard.xeno_balance_used = used
            wizard.xeno_balance_pending = pending
            wizard.xeno_balance_remaining = total - used - pending

    @api.onchange("holiday_status_id")
    def _onchange_xeno_holiday_status_id(self):
        if self.holiday_status_id.xeno_flexible_duration and not self.xeno_request_unit:
            self.xeno_request_unit = "full_day"

    @api.model
    def default_get(self, fields_list):
        res = super().default_get(fields_list)
        leave_id = self.env.context.get("default_leave_id")
        if leave_id:
            leave = self.env["hr.leave"].browse(leave_id)
            res.update({
                "holiday_status_id": leave.holiday_status_id.id,
                "request_date_from": leave.request_date_from,
                "request_date_to": leave.request_date_to,
                "request_hour_from": leave.request_hour_from,
                "request_hour_to": leave.request_hour_to,
                "xeno_request_unit": leave.xeno_request_unit or "full_day",
            })
        return res

    def action_apply(self):
        self.ensure_one()
        if not self.env.user.has_group(HR_OFFICER_GROUP):
            raise UserError(_("Only Time Off Officers can edit a submitted "
                               "leave application."))
        leave = self.leave_id
        before = _(
            "%(type)s, %(f)s → %(t)s",
            type=leave.holiday_status_id.display_name,
            f=leave.request_date_from, t=leave.request_date_to)
        vals = {
            "holiday_status_id": self.holiday_status_id.id,
            "request_date_from": self.request_date_from,
            "request_date_to": self.request_date_to,
        }
        if self.xeno_flexible_duration:
            vals["xeno_request_unit"] = self.xeno_request_unit
            if self.xeno_request_unit == "first_half":
                vals["request_date_from_period"] = "am"
                vals["request_date_to_period"] = "am"
            elif self.xeno_request_unit == "second_half":
                vals["request_date_from_period"] = "pm"
                vals["request_date_to_period"] = "pm"
            elif self.xeno_request_unit == "part_time":
                vals["request_hour_from"] = self.request_hour_from
                vals["request_hour_to"] = self.request_hour_to
        leave.sudo().write(vals)
        after = _(
            "%(type)s, %(f)s → %(t)s",
            type=self.holiday_status_id.display_name,
            f=self.request_date_from, t=self.request_date_to)
        leave.message_post(body=_(
            "HR Update by %(user)s: %(before)s changed to %(after)s. "
            "Reason: %(reason)s",
            user=self.env.user.name, before=before, after=after,
            reason=self.reason))
        return {"type": "ir.actions.act_window_close"}
