"""Teste les cotisations par catégorie de salarié produites à l'issue de l'étape preprocessing."""

from collections import OrderedDict

from openfisca_core.parameters.parameter_scale import ParameterScale
from openfisca_france.model.prelevements_obligatoires.prelevements_sociaux.cotisations_sociales.base import (
    cotisations_employeur_by_categorie_salarie,
    cotisations_salarie_by_categorie_salarie,
    )


from .cache import tax_benefit_system


cotisations_salarie_by_name = {
    "agff": {
        "start_non_null_date": "2001-04-01",
        "final_null_date": "2019-01-01",
        },
    "agirc_arrco": {
        "start_non_null_date": "2019-01-01",
        },
    "agirc": {
        "start_non_null_date": "1948-01-01",
        "final_null_date": "2019-01-01",
        },
    "apec": {
        "start_non_null_date": "1971-01-01",
        },
    "arrco": {
        "start_non_null_date": "1962-01-01",
        "final_null_date": "2019-01-01",
        },
    "asf": {
        "start_non_null_date": "1984-01-01",
        },
    "ceg": {
        "start_non_null_date": "2019-01-01",
        },
    "cet": {
        "start_non_null_date": "1997-01-01",
        "final_null_date": "2019-01-01",
        },
    "cet2019": {
        "start_non_null_date": "2019-01-01",
        },
    "chomage": {
        "start_non_null_date": "1959-01-01",
        "final_null_date": "2018-10-01",
        },
    "cnracl_s_ti": {
        "start_non_null_date": "1947-09-19",
        },
    "cnracl_s_nbi": {
        "start_non_null_date": "1947-09-19",
        },
    "excep_solidarite": {
        "start_non_null_date": "1982-11-01",
        "final_null_date": "2018-01-01",
        },
    "ircantec": {
        "start_non_null_date": "1971-01-01",
        },
    "maladie_alsace_moselle": {
        "start_non_null_date": "1989-09-01",
        },
    "maladie": {
        "start_non_null_date": "1967-10-01",
        "final_null_date": "2018-01-01",
        },
    "pension": {
        "start_non_null_date": "1925-01-01",
        },
    "rafp": {
        "start_non_null_date": "2005-01-01"
        },
    "vieillesse_deplafonnee": {
        "start_non_null_date": "2004-07-01"
        },
    "vieillesse_plafonnee": {
        "start_non_null_date": "1993-07-01",
        },
    }


def test_preprocessing():
    """Tests the result of parameters preprocessing."""
    parameters = tax_benefit_system.parameters
    assert set(parameters.cotsoc.cotisations_employeur.children.keys()) == set([
        'prive_cadre',
        'prive_non_cadre',
        'public_non_titulaire',
        'public_titulaire_etat',
        'public_titulaire_hospitaliere',
        'public_titulaire_militaire',
        'public_titulaire_territoriale',
        ]), "Les barèmes de cotisations employeur de certaines catégories de salariés sont manquants"

    assert set(parameters.cotsoc.cotisations_salarie.children.keys()) == set([
        'prive_cadre',
        'prive_non_cadre',
        'public_non_titulaire',
        'public_titulaire_etat',
        'public_titulaire_hospitaliere',
        # 'public_titulaire_militaire',  FIXME Il y en a sûrement mais pas actuellement
        'public_titulaire_territoriale',
        ]), "Les barèmes de cotisations salarié de certaines catégories instant_sde salariés sont manquants"

    categorie_salaries = [
        "prive_cadre",
        "prive_non_cadre",
        "public_non_titulaire",
        "public_titulaire_etat",
        "public_titulaire_hospitaliere",
        "public_titulaire_territoriale",
        ]

    for categorie_salarie in categorie_salaries:
        test = parameters.cotsoc.cotisations_salarie.children[categorie_salarie].children.keys()
        target = cotisations_salarie_by_categorie_salarie[categorie_salarie]
        assert set(test) == set(target), "Les barèmes de cotisations salarié {} ne sont pas les bons".format(
            categorie_salarie)

        test = parameters.cotsoc.cotisations_employeur.children[categorie_salarie].children.keys()
        target = cotisations_employeur_by_categorie_salarie[categorie_salarie]
        assert set(test) == set(target), "Les barèmes de cotisations employeur {} ne sont pas les bons".format(
            categorie_salarie)

    for categorie_salarie in categorie_salaries:
        cotisations_salaries = set(cotisations_salarie_by_categorie_salarie[categorie_salarie])
        for cotisation_salarie in sorted(cotisations_salaries):
            bareme = parameters.cotsoc.cotisations_salarie.children[categorie_salarie].children[cotisation_salarie]

            assert isinstance(bareme, ParameterScale), f"{cotisation_salarie} entry's class is {type(bareme)} which is not a ParameterScale"

            final_null_date = cotisations_salarie_by_name[cotisation_salarie].get("final_null_date")
            if final_null_date:
                thresholds = [
                    dict(
                        (parameter_at_instant.instant_str, parameter_at_instant.value)
                        for parameter_at_instant in bracket.threshold.values_list
                        )
                    for bracket in bareme.brackets
                    ]
                final_thresholds_by_instant_str = OrderedDict(sorted(threshold.items(), reverse = True)[0] for threshold in thresholds)
                assert all([final_threshold is None for final_threshold in final_thresholds_by_instant_str.values()]), "Barème salarié {} ne s'éteint pas (il devrait en {})".format(
                    cotisation_salarie,
                    final_null_date,
                    )
                assert max(final_thresholds_by_instant_str.keys()) == final_null_date, "Barème salarié {} ne s'éteint pas en {}".format(
                    cotisation_salarie,
                    final_null_date,
                    )

            start_non_null_date = cotisations_salarie_by_name[cotisation_salarie].get("start_non_null_date")
            if start_non_null_date:
                thresholds = [
                    dict(
                        (parameter_at_instant.instant_str, parameter_at_instant.value)
                        for parameter_at_instant in bracket.threshold.values_list
                        )
                    for bracket in bareme.brackets
                    ]
                start_thresholds_by_instant_str = OrderedDict(sorted(threshold.items())[0] for threshold in thresholds)
                assert all([start_threshold is not None for start_threshold in start_thresholds_by_instant_str.values()]), "Barème salarié {} ne commence pas à la bonne date (il devrait en {})".format(
                    cotisation_salarie,
                    start_non_null_date,
                    )
                assert min(start_thresholds_by_instant_str.keys()) == start_non_null_date, "Barème salarié {} ne commence pas en {}".format(
                    cotisation_salarie,
                    start_non_null_date,
                    )
