# -*- coding: utf-8 -*-
from datetime import date
from odoo import fields, models, api, _
from odoo.exceptions import Warning, UserError


class EmployeeGratuity(models.Model):
    _name = 'hr.gratuity'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    _description = "Employee Gratuity"

    state = fields.Selection([
        ('draft', 'Draft'),
        ('submit', 'Submitted'),
        ('approve', 'Approved'),
        ('cancel', 'Cancelled')],
        default='draft', track_visibility='onchange')
    name = fields.Char(string='Reference', required=True, copy=False,
                       readonly=True,
                       default=lambda self: _('New'))
    employee_id = fields.Many2one('hr.employee', string='Employee',
                                  required=True, help="Employee")
    employee_contract_type = fields.Selection([
        ('limited', 'Limited'),
        ('unlimited', 'Unlimited')], string='Contract Type', readonly=True,
        store=True, help="Choose the contract type."
                         "if contract type is limited then during gratuity settlement if you have not specify the end date for contract, gratuity configration of limited type will be taken or"
                         "if contract type is Unlimited then during gratuity settlement if you have specify the end date for contract, gratuity configration of limited type will be taken.")
    employee_joining_date = fields.Date(string='Joining Date', readonly=True,
                                        store=True, help="Employee joining date")
    wage_type = fields.Selection([('monthly', 'Monthly Fixed Wage'), ('hourly', 'Hourly Wage')],
                                 help="Select the wage type monthly or hourly")
    total_working_years = fields.Float(string='Total Years Worked', readonly=True, store=True,
                                       help="Total working years")
    employee_probation_years = fields.Float(string='Leaves Taken(Years)', readonly=True, store=True,
                                            help="Employee probation years")
    employee_gratuity_years = fields.Float(string='Gratuity Calculation Years',
                                           readonly=True, store=True, help="Employee gratuity years")
    employee_basic_salary = fields.Float(string='Basic Salary',
                                         readonly=True,
                                         help="Employee's basic salary.")
    employee_gratuity_duration = fields.Many2one('gratuity.configuration',
                                                 readonly=True,
                                                 string='Configuration Line')
    employee_gratuity_configuration = fields.Many2one('hr.gratuity.accounting.configuration',
                                                      readonly=True,
                                                      string='Gratuity Configuration')
    employee_gratuity_amount = fields.Float(string='Gratuity Payment', readonly=True, store=True,
                                            help="Gratuity amount for the employee. \it is calculated If the wage type is hourly then gratuity payment is calculated as employee basic salary * Employee Daily Wage Days * gratuity configration rule percentage * gratuity calculation years.orIf the wage type is monthly then gratuity payment is calculated as employee basic salary * (Working Days/Employee Daily Wage Days) * gratuity configration rule percentage * gratuity calculation years.")
    hr_gratuity_credit_account = fields.Many2one('account.account', help="Gratuity credit account")
    hr_gratuity_debit_account = fields.Many2one('account.account', help="Gratuity debit account")
    hr_gratuity_journal = fields.Many2one('account.journal', help="Gratuity journal")
    company_id = fields.Many2one('res.company', 'Company', required=True,
                                 default=lambda self: self.env.company, help="Company")
    currency_id = fields.Many2one(related="company_id.currency_id",
                                  string="Currency", readonly=True, help="Currency")

    @api.model
    def create(self, vals):
        """ assigning the sequence for the record """
        vals['name'] = self.env['ir.sequence'].next_by_code('hr.gratuity')
        return super(EmployeeGratuity, self).create(vals)

    @api.depends('employee_id')
    @api.onchange('employee_id')
    def _onchange_employee_id(self):
        """ calculating the gratuity pay based on the contract and gratuity
        configurations """
        if self.employee_id.id:
            current_date = date.today()
            probation_ids = self.env['hr.training'].search([('employee_id', '=', self.employee_id.id)])
            contract_ids = self.env['hr.contract'].search([('employee_id', '=', self.employee_id.id)])
            contract_sorted = contract_ids.sorted(lambda line: line.date_start)
            if not contract_sorted:
                raise Warning(_('No contracts found for the selected employee...!\n'
                                'Employee must have at least one contract to compute gratuity settelement.'))
            self.employee_joining_date = joining_date = contract_sorted[0].date_start
            employee_probation_days = 0
            # find total probation days
            for probation in probation_ids:
                start_date = probation.start_date
                end_date = probation.end_date
                employee_probation_days += (end_date - start_date).days
            # get running contract
            hr_contract_id = self.env['hr.contract'].search(
                [('employee_id', '=', self.employee_id.id), ('state', '=', 'open')])
            if len(hr_contract_id) > 1 or not hr_contract_id:
                raise Warning(_('Selected employee have multiple or no running contracts!'))

            self.wage_type = hr_contract_id.wage_type
            if self.wage_type == 'hourly':
                self.employee_basic_salary = hr_contract_id.hourly_wage
            else:
                self.employee_basic_salary = hr_contract_id.wage

            if hr_contract_id.date_end:
                self.employee_contract_type = 'limited'
                employee_working_days = (hr_contract_id.date_end - joining_date).days
                self.total_working_years = employee_working_days / 365
                self.employee_probation_years = employee_probation_days / 365
                employee_gratuity_years = (employee_working_days - employee_probation_days) / 365
                self.employee_gratuity_years = employee_gratuity_years
            else:
                self.employee_contract_type = 'unlimited'
                employee_working_days = (current_date - joining_date).days
                self.total_working_years = employee_working_days / 365
                self.employee_probation_years = employee_probation_days / 365
                employee_gratuity_years = (employee_working_days - employee_probation_days) / 365
                self.employee_gratuity_years = round(employee_gratuity_years, 2)

            gratuity_duration_id = False
            hr_accounting_configuration_id = self.env[
                'hr.gratuity.accounting.configuration'].search(
                [('active', '=', True), ('config_contract_type', '=', self.employee_contract_type),
                 '|', ('gratuity_end_date', '>=', current_date), ('gratuity_end_date', '=', False),
                 '|', ('gratuity_start_date', '<=', current_date), ('gratuity_start_date', '=', False)])
            if len(hr_accounting_configuration_id) > 1:
                raise UserError(_(
                    "There is a date conflict in Gratuity accounting configuration. "
                    "Please remove the conflict and try again!"))
            elif not hr_accounting_configuration_id:
                raise UserError(
                    _('No gratuity accounting configuration found '
                      'or please set proper start date and end date for gratuity configuration!'))
            # find configuration ids related to the gratuity accounting configuration
            self.employee_gratuity_configuration = hr_accounting_configuration_id.id
            conf_ids = hr_accounting_configuration_id.gratuity_configuration_table.mapped('id')
            hr_duration_config_ids = self.env['gratuity.configuration'].browse(conf_ids)
            for duration in hr_duration_config_ids:
                if duration.from_year and duration.to_year and duration.from_year <= self.total_working_years <= duration.to_year:
                    gratuity_duration_id = duration
                    break
                elif duration.from_year and not duration.to_year and duration.from_year <= self.total_working_years:
                    gratuity_duration_id = duration
                    break
                elif duration.to_year and not duration.from_year and self.total_working_years <= duration.to_year:
                    gratuity_duration_id = duration
                    break

            if gratuity_duration_id:
                self.employee_gratuity_duration = gratuity_duration_id.id
            else:
                raise Warning(_('No suitable gratuity durations found !'))
            # show warning when the employee's working years is less than
            # one year or no running employee found.
            if self.total_working_years < 1 and self.employee_id.id:
                raise Warning(_('Selected Employee is not eligible for Gratuity Settlement'))
            self.hr_gratuity_journal = hr_accounting_configuration_id.gratuity_journal.id
            self.hr_gratuity_credit_account = hr_accounting_configuration_id.gratuity_credit_account.id
            self.hr_gratuity_debit_account = hr_accounting_configuration_id.gratuity_debit_account.id

            if self.employee_gratuity_duration and self.wage_type == 'hourly':
                if self.employee_gratuity_duration.employee_working_days != 0:
                    if self.employee_id.resource_calendar_id and self.employee_id.resource_calendar_id.hours_per_day:
                        daily_wage = self.employee_basic_salary * self.employee_id.resource_calendar_id.hours_per_day
                    else:
                        daily_wage = self.employee_basic_salary * 8
                    working_days_salary = daily_wage * self.employee_gratuity_duration.employee_working_days
                    gratuity_pay_per_year = working_days_salary * self.employee_gratuity_duration.percentage
                    employee_gratuity_amount = gratuity_pay_per_year * self.employee_gratuity_years
                    self.employee_gratuity_amount = round(employee_gratuity_amount, 2)
                else:
                    raise Warning(_("Employee working days is not configured in "
                                    "the gratuity configuration..!"))
            elif self.employee_gratuity_duration and self.wage_type == 'monthly':
                if self.employee_gratuity_duration.employee_daily_wage_days != 0:
                    daily_wage = self.employee_basic_salary / self.employee_gratuity_duration.employee_daily_wage_days
                    working_days_salary = daily_wage * self.employee_gratuity_duration.employee_working_days
                    gratuity_pay_per_year = working_days_salary * self.employee_gratuity_duration.percentage
                    employee_gratuity_amount = gratuity_pay_per_year * self.employee_gratuity_years
                    self.employee_gratuity_amount = round(employee_gratuity_amount, 2)
                else:
                    raise Warning(_("Employee wage days is not configured in "
                                    "the gratuity configuration..!"))

    # Changing state to submit
    def submit_request(self):
        self.write({'state': 'submit'})

    # Canceling the gratuity request
    def cancel_request(self):
        self.write({'state': 'cancel'})

    # Set the canceled request to draft
    def set_to_draft(self):
        self.write({'state': 'draft'})

    # function for creating the account move with gratuity amount and
    # account credentials
    def approved_request(self):
        for hr_gratuity_id in self:
            debit_vals = {
                'name': hr_gratuity_id.employee_id.name,
                'account_id': hr_gratuity_id.hr_gratuity_debit_account.id,
                'partner_id': hr_gratuity_id.employee_id.address_home_id.id or False,
                'journal_id': hr_gratuity_id.hr_gratuity_journal.id,
                'date': date.today(),
                'debit': hr_gratuity_id.employee_gratuity_amount > 0.0 and hr_gratuity_id.employee_gratuity_amount or 0.0,
                'credit': hr_gratuity_id.employee_gratuity_amount < 0.0 and -hr_gratuity_id.employee_gratuity_amount or 0.0,
            }
            credit_vals = {
                'name': hr_gratuity_id.employee_id.name,
                'account_id': hr_gratuity_id.hr_gratuity_credit_account.id,
                'partner_id': hr_gratuity_id.employee_id.address_home_id.id or False,
                'journal_id': hr_gratuity_id.hr_gratuity_journal.id,
                'date': date.today(),
                'debit': hr_gratuity_id.employee_gratuity_amount < 0.0 and -hr_gratuity_id.employee_gratuity_amount or 0.0,
                'credit': hr_gratuity_id.employee_gratuity_amount > 0.0 and hr_gratuity_id.employee_gratuity_amount or 0.0,
            }
            vals = {
                'name': hr_gratuity_id.name + " - " + 'Gratuity for' + ' ' + hr_gratuity_id.employee_id.name,
                'narration': hr_gratuity_id.employee_id.name,
                'ref': hr_gratuity_id.name,
                'partner_id': hr_gratuity_id.employee_id.address_home_id.id or False,
                'journal_id': hr_gratuity_id.hr_gratuity_journal.id,
                'date': date.today(),
                'line_ids': [(0, 0, debit_vals), (0, 0, credit_vals)],
            }
            move = hr_gratuity_id.env['account.move'].create(vals)
            move.post()
        self.write({'state': 'approve'})


class EmployeeContractWage(models.Model):
    _inherit = 'hr.contract'

    # structure_type_id = fields.Many2one('hr.payroll.structure.type', string="Salary Structure Type")
    company_country_id = fields.Many2one('res.country', string="Company country", related='company_id.country_id',
                            readonly=True)
    wage_type = fields.Selection([('monthly', 'Monthly Fixed Wage'), ('hourly', 'Hourly Wage')])
    hourly_wage = fields.Monetary('Hourly Wage', digits=(16, 2), default=0, required=True, tracking=True,
                                  help="Employee's hourly gross wage.")
