# -*- coding: utf-8 -*-

import calendar
from datetime import date, datetime

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


class EmployeeReward(models.Model):
    _name = 'hr.employee.reward'
    _rec_name = 'allowance_name'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    line_ids_reward = fields.One2many(comodel_name='lines.ids.reward', inverse_name='employee_reward_id',
                                      string="Reward Line")
    date = fields.Date(default=lambda self: fields.Date.today(), string="Date Request",
                       required=True, tracking=True)
    date_from = fields.Date(string="Date From", tracking=True)
    date_to = fields.Date(string="Date To", tracking=True)
    allowance_reason = fields.Text(string="Reward Reason", required=True)
    allowance_name = fields.Many2one('hr.salary.rule', string="Allowance Name")
    percentage = fields.Float(string="Percentage%", default=100)
    amount = fields.Float(string="Amount")
    account_id = fields.Many2one('account.account')
    journal_id = fields.Many2one('account.journal', string='Payment Method')
    next_approve = fields.Text(string="Next Required Approval", compute="_get_nxt_approve")
    reward_type = fields.Selection(
        [('allowance', 'Allowance'), ('amount', 'Amount')], default='allowance')
    transfer_type = fields.Selection(
        [('accounting', 'Accounting'), ('payroll', 'Payroll')], default='accounting')
    state = fields.Selection(
        [('draft', 'Draft'), ('submitted', 'Submit'), ('hrm', 'HRM Approval'),
         ('done', 'GM Approval'), ('refused', 'Refused')], default='draft', tracking=True)
    benefits_discounts = fields.Many2one(comodel_name='hr.salary.rule', string='Rewards/Benefits')

    check_appraisal = fields.Boolean(string='Appraisal‏ Percentage', default=False)
    reward_once = fields.Boolean(string='Reward Once Yearly', default=False)

    company_id = fields.Many2one('res.company', string='Company',
                                 default=lambda self: self.env.company)

    def action_add_employees(self):
        self.ensure_one()
        ctx = dict(self.env.context)
        if not self.id:
            ctx.update({
                'default_reward_vals': {
                    'name': self.name,
                }
            })
        else:
            ctx['default_employee_reward_id'] = self.id

        if self.percentage:
            ctx['default_percentage'] = self.percentage

        ctx['default_employee_id'] = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)

        return {
            'name': _('Add Employees to Reward'),
            'view_mode': 'form',
            'res_model': 'employee.selection.wizard',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'context': ctx,
        }

    @api.onchange('amount')
    def chick_amount_positive(self):
        for item in self:
           if item.amount < 0:
              raise UserError(_('The Amount Must Be Greater Than Zero'))


    @api.depends('state')
    def _get_nxt_approve(self):
        for record in self:
            if record.state == "draft":
                record.next_approve = "Submit"
                for line in record.line_ids_reward:
                    line.reward_state = "draft"
            elif record.state == "submitted":
                record.next_approve = "HRM Approval"
                for line in record.line_ids_reward:
                    line.reward_state = "submitted"
            elif record.state == "hrm":
                record.next_approve = "GM Approval"
                for line in record.line_ids_reward:
                    line.reward_state = "hrm"
            elif record.state == "done":
                for line in record.line_ids_reward:
                    line.reward_state = "done"
            elif record.state == "refused":
                for line in record.line_ids_reward:
                    line.reward_state = "refused"

    def action_submit(self):
        if not self.line_ids_reward:
            raise UserError(_('Sorry, Can Not Request without The Employees'))
        self.state = "submitted"
        for line in self.line_ids_reward:
            line.check_reward_once()
            line.reward_state = "submitted"

    def recalculate(self):
        for line in self.line_ids_reward:
            # line.amount = line.amount
            # line.percentage = line.percentage
            line._compute_calculate_amount()

    def action_hrm(self):
        self.state = "hrm"
        for line in self.line_ids_reward:
            line.check_reward_once()
            line.reward_state = "hrm"

    def action_done(self):
        if self.transfer_type == 'accounting':
            for item in self:
                for record in item.line_ids_reward:
                    debit_line_vals = {
                        'name': record.employee_id.name,
                        'debit': record.amount,
                        'account_id': item.account_id.id,
                        'partner_id': record.employee_id.user_id.partner_id.id,
                        'analytic_account_id': record.employee_id.department_id.analytic_account_id.id
                    }
                    credit_line_vals = {
                        'name': record.employee_id.name,
                        'credit': record.amount,
                        'account_id': item.journal_id.default_account_id.id
                        #'partner_id': record.employee_id.user_id.partner_id.id
                    }
                    if not record.move_id:
                       move = record.env['account.move'].create({
                           'state': 'draft',
                           'journal_id': item.journal_id.id,
                           'date': item.date,
                           'ref': record.employee_id.name,
                           'line_ids': [(0, 0, debit_line_vals), (0, 0, credit_line_vals)],
                           'res_model': 'hr.employee.reward',
                           'res_id': self.id
                       })

                       record.move_id = move.id
            self.state = "done"
            for line in self.line_ids_reward:
                line.reward_state = "done"
        if self.transfer_type == 'payroll':
            last_day_of_current_month = date.today().replace(
                day=calendar.monthrange(date.today().year, date.today().month)[1])
            first_day_of_current_month = date.today().replace(day=1)
            for item in self:
                for record in item.line_ids_reward:
                    if record.employee_id.contract_id:

                        advantage_arc = record.env['contract.advantage'].create({
                            'benefits_discounts': item.benefits_discounts.id,
                            'type': 'customize',
                            'date_from': item.date_from,
                            'date_to': item.date_to,
                            'amount': record.amount,
                            'reward_id': True,
                            'employee_id': record.employee_id.id,
                            'contract_advantage_id': record.employee_id.contract_id.id,
                            'out_rule': True,
                            'state': 'confirm',
                            'comments': item.allowance_reason})
                        record.advantage_id = advantage_arc.id
                    else:
                        raise UserError(_(
                            'Employee "%s" has no contract Please create contract to add line to advantages')
                                                 % record.employee_id.name)

            self.state = "done"
            for line in self.line_ids_reward:
                line.reward_state = "done"

    def action_refuse(self):
        self.state = "refused"
        for line in self.line_ids_reward:
            line.reward_state = "refused"

    def re_draft(self):
        # when redraft cancel the created account move
        if self.transfer_type == 'payroll':
            for record in self.line_ids_reward:
                record.advantage_id.draft()
                record.advantage_id.unlink()
                record.reward_state = "draft"
            self.state = "draft"

        if self.transfer_type == 'accounting':
            if self.transfer_type == 'accounting':
                if self.line_ids_reward and self.line_ids_reward[0].move_id:
                    move_id_not_draft = False
                    for line in self.line_ids_reward:
                        if line.move_id.state == 'posted':
                            move_id_not_draft_name = line.move_id.name
                            move_id_not_draft = True
                    if move_id_not_draft:
                        raise UserError(_(
                            'You can not cancel account move "%s" in state not draft') % move_id_not_draft_name)
                    else:
                        for record in self.line_ids_reward:
                            # record.move_id.write({'state': 'canceled'})
                            record.move_id.unlink()
                            record.write({'move_id': False, })
                            #record.account_id = False
                            #record.journal_id = False
                            record.reward_state = "draft"
                        self.write({'state': 'draft'})
                        #self.account_id = False
                        #self.journal_id = False
                else:
                    self.write({
                        'state': 'draft',
                        #'account_id': False,
                        #'journal_id': False
                    })
                    for record in self.line_ids_reward:
                        record.write({
                            'move_id': False,
                            #'account_id': False,
                            #'journal_id': False,
                            'reward_state': 'draft'
                        })

    def unlink(self):
        for i in self:
            if i.state != 'draft':
                raise UserError(_('You can not delete record in state not in draft'))
            i.line_ids_reward.unlink()
        return super(EmployeeReward, self).unlink()

    @api.onchange('transfer_type', 'account_id', 'journal_id', 'line_ids_reward')
    def onchange_transfer_type(self):
        if self.transfer_type == 'payroll':
            self.account_id = False
            self.journal_id = False
            for line in self.line_ids_reward:
                line.account_id = False
                line.journal_id = False
        if self.transfer_type == 'accounting':
            for line in self.line_ids_reward:
                if self.state == 'hrm':
                    if not line.account_id:
                        line.account_id = self.account_id
                    if not line.journal_id:
                        line.journal_id = self.journal_id
                else:
                    line.account_id = False
                    line.journal_id = False

    @api.onchange('account_id')
    def onchange_account_id(self):
        for line in self.line_ids_reward:
            self.recalculate()
            line.account_id = self.account_id

    @api.onchange('journal_id')
    def onchange_journal_id(self):
        for line in self.line_ids_reward:
            self.recalculate()
            line.journal_id = self.journal_id


class HrEmployee(models.Model):
    _name = 'lines.ids.reward'

    def _domain_get_employee(self):
        return [('id', '!=', self.employee_id.id), ('state', '=', 'open')]

    employee_reward_id = fields.Many2one('hr.employee.reward', string='Employee', required=True)
    employee_id = fields.Many2one('hr.employee', string='Employee', required=True,
                                  domain=lambda self: self._domain_get_employee())
    amount = fields.Float(string="Amount", compute='_compute_calculate_amount', store=True)
    account_id = fields.Many2one('account.account', string='Account')
    journal_id = fields.Many2one('account.journal', string='Payment Method')
    percentage = fields.Float(string="Percentage%")
    move_id = fields.Many2one('account.move')
    contract_advantage_id = fields.Many2one('hr.contract')
    reward_state = fields.Selection(
        [('draft', 'Draft'), ('submitted', 'Submit'), ('hrm', 'HRM Approval'),
         ('done', 'GM Approval'), ('refused', 'Refused')], default='draft')

    amount_base = fields.Float(string="Amount Base", store=True)
    check_appraisal = fields.Boolean('Appraisal‏ Percentage', related='employee_reward_id.check_appraisal', store=True)
    transfer_type = fields.Selection(related='employee_reward_id.transfer_type', string='Transfer type')

    reward_once = fields.Boolean(related='employee_reward_id.reward_once', store=True)
    date = fields.Date(related='employee_reward_id.date', string='Reward Once Yearly', store=True)

    advantage_id = fields.Many2one(comodel_name='contract.advantage', string='Allowance Employee')

    reward_type = fields.Selection(related='employee_reward_id.reward_type', string='Reward Type', store=True)

    @api.onchange('amount_base')
    def chick_amount_base_positive(self):
        for item in self:
           if item.amount_base < 0:
              raise UserError(_('The Employee %s Amount Must Be Greater Than Zero')% item.employee_id.name)


    # Select employee once in reward Line
    @api.onchange('employee_id')
    def select_employee_once(self):
        employee_ids = self.env['hr.employee'].search([('state', '=', 'open')]).ids

        for line in self.employee_reward_id.line_ids_reward:
            if line.employee_id:
                if line.employee_id.id in employee_ids:
                    employee_ids.remove(line.employee_id.id)

        return {'domain': {'employee_id': [('id', 'in', employee_ids)]}}

    def get_salary_rules_account(self, record_id, amount, items):
        record = self.env['hr.salary.rule.line'].create({
            'salary_rule_id': record_id.id,
            'amount': amount,
        })
        items.append(record.id)

    def compute_salary_rule(self, record_id, item, items):
        for record in self:
            if not record.employee_id.id: continue
            contract = self.env['hr.contract'].search([('employee_id', '=', record.employee_id.id)])
            localdict = dict(employee=record.employee_id.id, contract=contract)
            amount, total = 0.0, 0.0

            if item.amount_select == 'fix':
                if contract.advantages:
                    for con in contract.advantages:
                        if item.id == con.benefits_discounts.id:
                            if con.type == 'exception':
                                if con.amount > item._compute_rule(localdict)[0] or con.amount == \
                                        item._compute_rule(localdict)[0]:
                                    pass
                                elif con.amount < item._compute_rule(localdict)[0]:
                                    total = item._compute_rule(localdict)[0] - con.amount
                            elif con.type == 'customize':
                                total = con.amount
                            amount = 0
                            amount += total
                        else:
                            amount = 0
                            amount += item._compute_rule(localdict)[0]
                else:
                    amount += item._compute_rule(localdict)[0]

            elif item.amount_select == 'percentage':
                if contract and contract.advantages:
                    for con in contract.advantages:
                        if item.id == con.benefits_discounts.id:
                            if con.type == 'exception':
                                if con.amount > item._compute_rule(localdict)[0] or con.amount == \
                                        item._compute_rule(localdict)[0]:
                                    pass
                                elif con.amount < item._compute_rule(localdict)[0]:
                                    total = item._compute_rule(localdict)[0] - con.amount
                            elif con.type == 'customize':
                                total = con.amount
                            amount = 0
                            amount += total
                            break
                        else:
                            if amount:
                                pass
                            else:
                                amount += item._compute_rule(localdict)[0]
                else:
                    amount += item._compute_rule(localdict)[0]

            else:
                if contract.advantages:
                    for con in contract.advantages:
                        if item.id == con.benefits_discounts.id:
                            if con.type == 'exception':
                                if con.amount > item._compute_rule(localdict)[0] or con.amount == \
                                        item._compute_rule(localdict)[0]:
                                    pass
                                elif con.amount < item._compute_rule(localdict)[0]:
                                    total = item._compute_rule(localdict)[0] - con.amount
                            elif con.type == 'customize':
                                total = con.amount
                            amount = 0
                            amount += total
                        else:
                            if amount:
                                pass
                            else:
                                amount = 0
                                amount += item._compute_rule(localdict)[0]
                else:
                    amount += item._compute_rule(localdict)[0]

            return amount

    @api.depends('percentage', 'employee_reward_id', 'employee_id', 'account_id', 'journal_id','amount_base')
    def _compute_calculate_amount(self):
        for line in self:
            if line.check_appraisal == True:
                self.get_percentage_appraisal()
            percentage = line.percentage
            if line.employee_reward_id.reward_type == 'allowance':
                if line.employee_reward_id.allowance_name:
                    items = []
                    for item in line.employee_reward_id.allowance_name:
                        total = 0.0
                        record_id = self.env['hr.salary.rule'].search([('id', '=', item.id)])
                        total = self.compute_salary_rule(record_id, item, items) or 0
                    amount = (total * percentage) / 100
                    line.amount = amount
                    amount_base = total
                    line.amount_base = amount_base
            elif line.employee_reward_id.reward_type == 'amount':
                amount_up = line.employee_reward_id.amount
                if amount_up > 0:
                   amount = (amount_up * percentage) / 100
                   line.amount = amount
                   amount_base = amount_up 
                   line.amount_base = amount_base
                else:
                   line.amount = (line.amount_base * percentage) / 100

            else:
                line.amount = 0

    @api.model
    def default_get(self, fields):
        res = super(HrEmployee, self).default_get(fields)
        if self._context.get('percentage'):
            res['percentage'] = self._context.get('percentage')
        if self._context.get('account_id') and self._context.get('journal_id'):
            res['account_id'] = self._context.get('account_id')
            res['journal_id'] = self._context.get('journal_id')
        return res

    # get percentage from performance appraisal
    def get_percentage_appraisal(self):
        Module = self.env['ir.module.module'].sudo()
        modules = Module.search([('state', '=', 'installed'), ('name', '=', 'exp_hr_appraisal')])

        for line in self:
            if modules:
                emp_appraisal = self.env['hr.employee.appraisal'].search([('employee_id', '=', line.employee_id.id),
                                                                          ('state', '!=', 'draft'),
                                                                          ('appraisal_type', '=', 'performance')],
                                                                         order='appraisal_date desc', limit=1)
                level_achieved = emp_appraisal.level_achieved
                if line.check_appraisal:
                    if emp_appraisal:
                        line.percentage = level_achieved
                    else:
                        line.percentage = 0

    # To Cannot Take More Than Once Reward In The Same Year

    @api.constrains('employee_id', 'date', 'reward_once')
    def check_reward_once(self):
        for rec in self:
            if rec.date:
                current_year = datetime.strptime(str(rec.date), "%Y-%m-%d").date().year
                last_reward = rec.search([('id', '!=', rec.id), ('employee_id', '=', rec.employee_id.id),
                                          ('reward_state', 'not in', ('draft', 'refused')),
                                          ('reward_once', '=', True)], order='date desc', limit=1).date
                if last_reward:
                    last_year = datetime.strptime(str(last_reward), "%Y-%m-%d").date().year
                    if current_year == last_year and rec.reward_once:
                        raise UserError(_('Sorry, The Employee %s Cannot be Taking More Than Once Reward '
                                                   'In The Same Year %s') % (rec.employee_id.name, current_year))

    def unlink(self):
        for i in self:
            if i.reward_state != 'draft':
                raise UserError(_('You can not delete record in state not in draft'))
        return super(HrEmployee, self).unlink()
