"""Functions to compute unemployment benefits (Arbeitslosengeld)."""
import numpy as np

from _gettsim.piecewise_functions import piecewise_polynomial
from _gettsim.taxes.eink_st import _eink_st_tarif
from _gettsim.transfers.rente import ges_rente_regelaltersgrenze


def arbeitsl_geld_m(
    anz_kinder_tu: int,
    arbeitsl_geld_berechtigt: bool,
    arbeitsl_geld_eink_vorj_proxy: float,
    arbeitsl_geld_params: dict,
) -> float:
    """Calculate individual unemployment benefit.

    Parameters
    ----------
    anz_kinder_tu
        See :func:`anz_kinder_tu`.
    arbeitsl_geld_berechtigt
        See :func:`arbeitsl_geld_berechtigt`.
    arbeitsl_geld_eink_vorj_proxy
        See :func:`arbeitsl_geld_eink_vorj_proxy`.
    arbeitsl_geld_params
        See params documentation :ref:`arbeitsl_geld_params <arbeitsl_geld_params>`.

    Returns
    -------

    """

    if arbeitsl_geld_berechtigt:
        if anz_kinder_tu == 0:
            arbeitsl_geld_satz = arbeitsl_geld_params["satz_ohne_kinder"]
        else:
            arbeitsl_geld_satz = arbeitsl_geld_params["satz_mit_kindern"]

        out = arbeitsl_geld_eink_vorj_proxy * arbeitsl_geld_satz
    else:
        out = 0.0

    return out


def arbeitsl_geld_restl_anspruchsd(
    alter: int,
    soz_vers_pflicht_5j: float,
    anwartschaftszeit: bool,
    m_durchg_alg1_bezug: float,
    arbeitsl_geld_params: dict,
) -> int:
    """Calculate the remaining amount of months a person can receive unemployment
    benefit this year.

    Parameters
    ----------
    alter
        See basic input variable :ref:`alter <alter>`.
    soz_vers_pflicht_5j
        See basic input variable :ref:`soz_vers_pflicht_5j <soz_vers_pflicht_5j>`.
    anwartschaftszeit
        See basic input variable :ref:`anwartschaftszeit <anwartschaftszeit>`.
    m_durchg_alg1_bezug
        See basic input variable :ref:`m_durchg_alg1_bezug <m_durchg_alg1_bezug>`.
    arbeitsl_geld_params
        See params documentation :ref:`arbeitsl_geld_params <arbeitsl_geld_params>`.

    Returns
    -------

    """
    nach_alter = piecewise_polynomial(
        alter,
        thresholds=[
            *list(arbeitsl_geld_params["anspruchsdauer"]["nach_alter"]),
            np.inf,
        ],
        rates=np.array(
            [[0] * len(arbeitsl_geld_params["anspruchsdauer"]["nach_alter"])]
        ),
        intercepts_at_lower_thresholds=list(
            arbeitsl_geld_params["anspruchsdauer"]["nach_alter"].values()
        ),
    )
    nach_versich_pfl = piecewise_polynomial(
        soz_vers_pflicht_5j,
        thresholds=[
            *list(
                arbeitsl_geld_params["anspruchsdauer"][
                    "nach_versicherungspflichtige_monate"
                ]
            ),
            np.inf,
        ],
        rates=np.array(
            [
                [0]
                * len(
                    arbeitsl_geld_params["anspruchsdauer"][
                        "nach_versicherungspflichtige_monate"
                    ]
                )
            ]
        ),
        intercepts_at_lower_thresholds=list(
            arbeitsl_geld_params["anspruchsdauer"][
                "nach_versicherungspflichtige_monate"
            ].values()
        ),
    )
    if anwartschaftszeit:
        anspruchsdauer_gesamt = min(nach_alter, nach_versich_pfl)
        out = max(anspruchsdauer_gesamt - m_durchg_alg1_bezug, 0)
    else:
        out = 0

    return out


def arbeitsl_geld_berechtigt(
    alter: int,
    arbeitssuchend: bool,
    arbeitsl_geld_restl_anspruchsd: int,
    arbeitsstunden_w: float,
    arbeitsl_geld_params: dict,
    geburtsjahr: int,
    ges_rente_params: dict,
) -> bool:
    """Check eligibility for unemployment benefit.

    Parameters
    ----------
    alter
        See basic input variable :ref:`alter <alter>`.
    arbeitssuchend
        See basic input variable :ref:`arbeitssuchend <arbeitssuchend>`.
    arbeitsl_geld_restl_anspruchsd
        See :func:`arbeitsl_geld_restl_anspruchsd`.
    arbeitsstunden_w
        See basic input variable :ref:`arbeitsstunden_w <arbeitsstunden_w>`.
    arbeitsl_geld_params
        See params documentation :ref:`arbeitsl_geld_params <arbeitsl_geld_params>`.
    geburtsjahr
        See basic input variable :ref:`geburtsjahr <geburtsjahr>`.
    ges_rente_params
        See params documentation :ref:`ges_rente_params <ges_rente_params>`.

    Returns
    -------

    """
    regelaltersgrenze = ges_rente_regelaltersgrenze(geburtsjahr, ges_rente_params)

    out = (
        arbeitssuchend
        and (arbeitsl_geld_restl_anspruchsd > 0)
        and (alter < regelaltersgrenze)
        and (arbeitsstunden_w < arbeitsl_geld_params["stundengrenze"])
    )

    return out


def arbeitsl_geld_eink_vorj_proxy(
    _ges_rentenv_beitr_bemess_grenze_m: float,
    bruttolohn_vorj_m: float,
    arbeitsl_geld_params: dict,
    eink_st_params: dict,
    eink_st_abzuege_params: dict,
    soli_st_params: dict,
) -> float:
    """Approximate last years income for unemployment benefit.

    Parameters
    ----------
    _ges_rentenv_beitr_bemess_grenze_m
        See :func:`_ges_rentenv_beitr_bemess_grenze_m`.
    bruttolohn_vorj_m
        See basic input variable :ref:`bruttolohn_vorj_m <bruttolohn_vorj_m>`.
    arbeitsl_geld_params
        See params documentation :ref:`arbeitsl_geld_params <arbeitsl_geld_params>`.
    eink_st_params
        See params documentation :ref:`eink_st_params <eink_st_params>`.
    eink_st_abzuege_params
        See params documentation :ref:`eink_st_abzuege_params <eink_st_abzuege_params>`.
    soli_st_params
        See params documentation :ref:`soli_st_params <soli_st_params>`.

    Returns
    -------

    """
    # Relevant wage is capped at the contribution thresholds
    max_wage = min(bruttolohn_vorj_m, _ges_rentenv_beitr_bemess_grenze_m)

    # We need to deduct lump-sum amounts for contributions, taxes and soli
    prox_ssc = arbeitsl_geld_params["soz_vers_pausch"] * max_wage

    # Fictive taxes (Lohnsteuer) are approximated by applying the wage to the tax tariff
    # Caution: currently wrong calculation due to
    # 12 * max_wage - eink_st_abzuege_params["werbungskostenpauschale"] not being
    # the same as zu versteuerndes einkommen
    # waiting for PR Lohnsteuer #150 to be merged to correct this problem
    prox_tax = _eink_st_tarif(
        12 * max_wage - eink_st_abzuege_params["werbungskostenpauschale"],
        eink_st_params,
    )
    prox_soli = piecewise_polynomial(
        prox_tax,
        thresholds=soli_st_params["soli_st"]["thresholds"],
        rates=soli_st_params["soli_st"]["rates"],
        intercepts_at_lower_thresholds=soli_st_params["soli_st"][
            "intercepts_at_lower_thresholds"
        ],
    )
    out = max_wage - prox_ssc - prox_tax / 12 - prox_soli / 12
    out = max(out, 0.0)
    return out
