# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.

from datetime import date
from pprint import pformat

import logging
_logger = logging.getLogger(__name__)


def ir_5ta_cat(payslip, categories, worked_days, inputs):
    basic_wage = categories.BASIC
    if payslip.dict.contract_id.pe_payroll_config_value('ee_5ta_cat_exempt'):
        return 0.0, 0.0
    
    pay_periods_in_year = payslip.pay_periods_in_year
    uit = payslip.rule_parameter('pe_uit')
    payslip_date_end = payslip.dict.date_to
    
    #    IF this is the last payroll in June or December
    #    THEN we need to 'true up' the last two quarters of withholding (e.g. give a refund)
    last_payslip_june = payslip_date_end.month == 6 and payslip_date_end.day == 30
    # NOTE we do NOT currently support 'catch up' in June.  Our formula genearlly already catches up.
    last_payslip_june = False
    last_payslip_december = payslip_date_end.month == 12 and payslip_date_end.day == 31
    
    wage_period = categories.GROSS
    if not any((basic_wage, wage_period, last_payslip_june, last_payslip_december)):
        return 0.0, 0.0
    
    period_additional_wage = max(wage_period - basic_wage, 0.0)  # 0.0 or positive
    
    year = payslip_date_end.year
    next_year = date(year+1, 1, 1)
    prior_wage_year = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01')
    pay_periods_at_current = round(((next_year - payslip_date_end).days / 365) * pay_periods_in_year) + 1.0
    
    wage_year = (basic_wage * pay_periods_at_current) + prior_wage_year
    
    #    IF employee's `first_contract_date` is in current year
    #    THEN we can pro-rate the period (reduce withholding)
    # TODO replace with just date_from on contract or something
    # we are told that every year new contracts will be needed
    date_hired = payslip.dict.contract_id.first_contract_date
    payslip_date_end = payslip.dict.date_to
    hired_in_year = date_hired.year == payslip_date_end.year
    periods_in_year_eligible = pay_periods_in_year
    if hired_in_year:
        periods_in_year_eligible = round(((next_year - date_hired).days / 365) * pay_periods_in_year)
    
    # normalize 1era Gratification
    if hired_in_year and date_hired.month > 6:
        wage_gratif_1 = 0.0
    elif hired_in_year:
        wage_gratif_1 = basic_wage / 6 * (6 - date_hired.month + 1)
    else:
        wage_gratif_1 = basic_wage
    
    # normalize 2da Gratification
    if hired_in_year and date_hired.month > 6:
        wage_gratif_2 = basic_wage / 6 * (12 - date_hired.month + 1)
    else:
        wage_gratif_2 = basic_wage
    
    wage_year += wage_gratif_1 + wage_gratif_2
    cat_ley = (wage_gratif_1 + wage_gratif_2) * (payslip.rule_parameter('ee_ir_5ta_cat_ley_29351') / 100.0)
    wage_year += cat_ley
    wage_year += period_additional_wage
    
    over_7uit = wage_year - (7.0 * uit)
    total_tax = 0.0
    if over_7uit > 0.0:
        total_tax = 0.0
        last_uit = 0.0
        for _uit, rate in payslip.rule_parameter('ee_ir_5ta_cat'):
            # marginal brackets
            _uit = float(_uit)
            if over_7uit > (last_uit * uit):
                eligible_wage = min(over_7uit, _uit * uit) - (last_uit * uit)
                if eligible_wage > 0.0:
                    total_tax += eligible_wage * (rate / 100.0)
                else:
                    break
            else:
                break
            last_uit = _uit

    # if total_tax:
    ytd_tax = -payslip.sum_category('EE_PE_IR_5TA_CAT', str(year) + '-01-01', str(year+1) + '-01-01')
    
    if last_payslip_june or last_payslip_december:
        if last_payslip_june:
            # does not work right because the gratif_2 is already there
            total_tax /= 2
        # remaining_tax may flip signs
        remaining_tax = -(total_tax - ytd_tax)
        if not wage_period:
            # to give refund, cannot normalize to wage
            return remaining_tax, 100.0
        return wage_period,  (remaining_tax / wage_period * 100.0)
    
    tax = -(total_tax - ytd_tax) / pay_periods_at_current
    # uncomment to see a lot of detail
    # _logger.info('ir_5ta_cat locals: ' + str(pformat(locals())))
    return wage_period, (tax / wage_period * 100.0)
