# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo.exceptions import UserError
from ..federal.fed_940 import futa_wage, futa_wage_ytd
from ..federal.fed_941 import fit_wage, fit_wage_ytd

# import logging
# _logger = logging.getLogger(__name__)

suta_wage = futa_wage
suta_wage_ytd = futa_wage_ytd
sit_wage = fit_wage
sit_wage_ytd = fit_wage_ytd


def _state_applies(payslip, state_code):
    return state_code == payslip.contract_id.us_payroll_config_value('state_code')


# Export for eval context
is_us_state = _state_applies


def _general_rate(payslip, wage, ytd_wage, wage_base=None, wage_start=None, rate=None):
    """
    Function parameters:
    wage_base, wage_start, rate can either be strings (rule_parameters) or floats
    :return: result, result_rate(wage, percent)
    """

    # Resolve parameters.  On exception, return (probably missing a year, would rather not have exception)
    if wage_base and isinstance(wage_base, str):
        try:
            wage_base = payslip.rule_parameter(wage_base)
        except (KeyError, UserError):
            return 0.0, 0.0

    if wage_start and isinstance(wage_start, str):
        try:
            wage_start = payslip.rule_parameter(wage_start)
        except (KeyError, UserError):
            return 0.0, 0.0

    if rate and isinstance(rate, str):
        try:
            rate = payslip.rule_parameter(rate)
        except (KeyError, UserError):
            return 0.0, 0.0

    if not rate:
        return 0.0, 0.0
    else:
        # Rate assumed positive percentage!
        rate = -rate

    if wage_base:
        remaining = wage_base - ytd_wage
        if remaining < 0.0:
            result = 0.0
        elif remaining < wage:
            result = remaining
        else:
            result = wage

        # _logger.warn('  wage_base method result: ' + str(result) + ' rate: ' + str(rate))
        return result, rate
    if wage_start:
        if ytd_wage >= wage_start:
            # _logger.warn('  wage_start 1 method result: ' + str(wage) + ' rate: ' + str(rate))
            return wage, rate
        if ytd_wage + wage <= wage_start:
            # _logger.warn('  wage_start 2 method result: ' + str(0.0) + ' rate: ' + str(0.0))
            return 0.0, 0.0
        # _logger.warn('  wage_start 3 method result: ' + str((wage - (wage_start - ytd_wage))) + ' rate: ' + str(rate))
        return (wage - (wage_start - ytd_wage)), rate

    # If the wage doesn't have a start or a base
    # _logger.warn('  basic result: ' + str(wage) + ' rate: ' + str(rate))
    return wage, rate


def general_state_unemployment(payslip, categories, worked_days, inputs, wage_base=None, wage_start=None, rate=None, state_code=None):
    """
    Returns SUTA eligible wage and rate.
    WAGE = GROSS + DED_FUTA_EXEMPT

    The contract's `futa_type` determines if SUTA should be collected.

    :return: result, result_rate(wage, percent)
    """

    if not _state_applies(payslip, state_code):
        return 0.0, 0.0

    # Determine Eligible.
    if payslip.contract_id.futa_type in (payslip.contract_id.FUTA_TYPE_EXEMPT, payslip.contract_id.FUTA_TYPE_BASIC):
        return 0.0, 0.0

    # Determine Wage
    wage = suta_wage(payslip, categories)
    if not wage:
        return 0.0, 0.0

    ytd_wage = suta_wage_ytd(payslip, categories)

    return _general_rate(payslip, wage, ytd_wage, wage_base=wage_base, wage_start=wage_start, rate=rate)


def general_state_income_withholding(payslip, categories, worked_days, inputs, wage_base=None, wage_start=None, rate=None, state_code=None):
    """
    Returns SIT eligible wage and rate.
    WAGE = GROSS + DED_FIT_EXEMPT

    :return: result, result_rate (wage, percent)
    """
    if not _state_applies(payslip, state_code):
        return 0.0, 0.0

    if payslip.contract_id.us_payroll_config_value('state_income_tax_exempt'):
        return 0.0, 0.0

    # Determine Wage
    ytd_wage = sit_wage_ytd(payslip, categories)

    wage = sit_wage(payslip, categories)
    result, result_rate = _general_rate(payslip, wage, ytd_wage, wage_base=wage_base, wage_start=wage_start, rate=rate)
    additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
    if additional:
        tax = result * (result_rate / 100.0)
        tax -= additional  # assumed result_rate is negative and that the 'additional' should increase it.
        return result, ((tax / result) * 100.0)
    return result, result_rate
