# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import api, models, fields


class HrAttendanceOvertimeLine(models.Model):
    _name = 'hr.attendance.overtime.line'
    _description = "Attendance Overtime Line"
    _rec_name = 'employee_id'
    _order = 'time_start'

    employee_id = fields.Many2one(
        'hr.employee', string="Employee",
        required=True, ondelete='cascade', index=True)
    company_id = fields.Many2one(related='employee_id.company_id')

    date = fields.Date(string='Day', index=True, required=True)
    status = fields.Selection([
            ('to_approve', "To Approve"),
            ('approved', "Approved"),
            ('refused', "Refused")
        ],
        compute='_compute_status',
        required=True, store=True, readonly=False, precompute=True,
    )
    duration = fields.Float(string='Extra Hours', default=0.0, required=True)
    manual_duration = fields.Float(  # TODO -> real_duration for easier upgrade
        string='Extra Hours (encoded)',
        compute='_compute_manual_duration',
        store=True, readonly=False,
    )

    time_start = fields.Datetime(string='Start')  # time_start will be equal to attendance.check_in
    time_stop = fields.Datetime(string='Stop')  # time_stop will be equal to attendance.check_out
    amount_rate = fields.Float("Overtime pay rate", required=True, default=1.0)

    is_manager = fields.Boolean(compute="_compute_is_manager")

    rule_ids = fields.Many2many("hr.attendance.overtime.rule", string="Applied Rules")

    # in payroll: rate, work_entry_type
    # in time_off: convertible_to_time_off

    # Check no overlapping overtimes for the same employee.
    # Technical explanation: Exclude constraints compares the given expression on rows 2 by 2 using the given operator; && on tsrange is the intersection.
    # cf: https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-EXCLUSION
    # for employee_id we compare [employee_id -> employee_id] ranges bc raw integer is not supported (?)
    # _overtime_no_overlap_same_employee = models.Constraint("""
    #     EXCLUDE USING GIST (
    #         tsrange(time_start, time_stop, '()') WITH &&,
    #         int4range(employee_id, employee_id, '[]') WITH =
    #     )
    #     """,
    #     "Employee cannot have overlapping overtimes",
    # )
    _overtime_start_before_end = models.Constraint(
        'CHECK (time_stop > time_start)',
        'Starting time should be before end time.',
    )

    @api.depends('employee_id')
    def _compute_status(self):
        for overtime in self:
            if not overtime.status:
                overtime.status = 'to_approve' if overtime.employee_id.company_id.attendance_overtime_validation == 'by_manager' else 'approved'

    @api.depends('duration')
    def _compute_manual_duration(self):
        for overtime in self:
            overtime.manual_duration = overtime.duration

    @api.depends('employee_id')
    def _compute_is_manager(self):
        has_manager_right = self.env.user.has_group('hr_attendance.group_hr_attendance_manager')
        has_officer_right = self.env.user.has_group('hr_attendance.group_hr_attendance_officer')
        for overtime in self:
            overtime.is_manager = (
                has_manager_right or
                (
                    has_officer_right
                    and overtime.employee_id.attendance_manager_id == self.env.user
                )
            )

    def action_approve(self):
        self.write({'status': 'approved'})

    def action_refuse(self):
        self.write({'status': 'refused'})

    def _linked_attendances(self):
        return self.env['hr.attendance'].search([
            ('check_in', 'in', self.mapped('time_start')),
            ('employee_id', 'in', self.employee_id.ids),
        ])

    def write(self, vals):
        if any(key in vals for key in ['status', 'manual_duration', 'duration']):
            attendances = self._linked_attendances()
            if any(key in vals for key in ['status', 'manual_duration']):
                self.env.add_to_compute(
                    attendances._fields['overtime_status'],
                    attendances
                )
                self.env.add_to_compute(
                    attendances._fields['validated_overtime_hours'],
                    attendances
                )
            if 'duration' in vals:
                self.env.add_to_compute(
                    attendances._fields['overtime_hours'],
                    attendances
                )
                self.env.add_to_compute(
                    attendances._fields['expected_hours'],
                    attendances
                )
        return super().write(vals)
