import attr

from django.http import HttpRequest, HttpResponse, JsonResponse, HttpResponseNotFound

from staff.lib.decorators import auth_by_tvm_only
from staff.lib.oebs import wrap_oebs_errors

from staff.budget_position.controllers import check_if_hr_product_changed_controller
from staff.budget_position.forms import (
    CheckIfHrProductChangedForm,
    GetBonusSchemeForm,
    GetReviewSchemeForm,
    GetRewardSchemeForm,
)
from staff.budget_position.workflow_service import (
    BudgetPositionsRepository,
    GetSchemeDetails,
    GetSchemeRequest,
    GradeCalculator,
    OEBSService,
    SchemesCalculator,
    StaffService,
    TableflowService,
)


def _build_usecase() -> GetSchemeDetails:
    table_flow_service = TableflowService()
    staff_service = StaffService()
    oebs_service = OEBSService(BudgetPositionsRepository())
    grade_calculator = GradeCalculator(oebs_service, staff_service)
    schemes_calculator = SchemesCalculator(table_flow_service, staff_service, grade_calculator)
    get_schemes_details_usecase = GetSchemeDetails(schemes_calculator, grade_calculator, staff_service, oebs_service)
    return get_schemes_details_usecase


@auth_by_tvm_only(['femida'])
def bonus_scheme_view(request: HttpRequest) -> HttpResponse:
    form = GetBonusSchemeForm(data=request.GET)
    if not form.is_valid():
        return JsonResponse(form.errors_as_dict(), status=400)

    get_schemes_details_usecase = _build_usecase()

    bonus_scheme_details = get_schemes_details_usecase.get_bonus_scheme(
        GetSchemeRequest(
            department_id=form.cleaned_data['department'].id,
            occupation_id=form.cleaned_data['occupation'].pk,
            grade_level=form.cleaned_data['grade_level'],
        )
    )

    if not bonus_scheme_details:
        return HttpResponseNotFound()

    response = {
        'scheme_id': bonus_scheme_details.scheme_id,
        'name': bonus_scheme_details.name,
        'description': bonus_scheme_details.description,
        'non_review_bonus': bonus_scheme_details.non_review_bonus,
    }

    return JsonResponse(response, status=200)


@auth_by_tvm_only(['femida'])
def review_scheme_view(request: HttpRequest) -> HttpResponse:
    form = GetReviewSchemeForm(data=request.GET)
    if not form.is_valid():
        return JsonResponse(form.errors_as_dict(), status=400)

    get_schemes_details_usecase = _build_usecase()
    review_scheme_details = get_schemes_details_usecase.get_review_scheme(
        GetSchemeRequest(
            department_id=form.cleaned_data['department'].id,
            occupation_id=form.cleaned_data['occupation'].pk,
            grade_level=form.cleaned_data['grade_level'],
        )
    )

    if not review_scheme_details:
        return HttpResponseNotFound()

    response = {
        'scheme_id': review_scheme_details.scheme_id,
        'name': review_scheme_details.name,
        'description': review_scheme_details.description,
        'schemes_line_id': review_scheme_details.schemes_line_id,
        'schemes_line_description': review_scheme_details.schemes_line_description,
        'target_bonus': review_scheme_details.target_bonus,
        'grant_type': review_scheme_details.grant_type,
        'grant_type_description': review_scheme_details.grant_type_description,
        'has_review': review_scheme_details.has_review,
        'review_bonus': review_scheme_details.review_bonus,
    }

    return JsonResponse(response, status=200)


@wrap_oebs_errors
@auth_by_tvm_only(['femida'])
def reward_scheme_view(request: HttpRequest) -> HttpResponse:
    form = GetRewardSchemeForm(data=request.GET)
    if not form.is_valid():
        return JsonResponse(form.errors_as_dict(), status=400)

    get_schemes_details_usecase = _build_usecase()
    reward_scheme_details = get_schemes_details_usecase.get_reward_scheme(
        GetSchemeRequest(
            department_id=form.cleaned_data['department'].id,
            occupation_id=form.cleaned_data['occupation'].pk,
            grade_level=form.cleaned_data['grade_level'],
            is_internship=form.cleaned_data['is_internship'],
            femida_professional_level=form.cleaned_data['professional_level'],
            is_main_work_place=form.cleaned_data['is_main_work_place'],
            contract_term=form.cleaned_data['contract_term'],
            contract_term_date=form.cleaned_data['contract_term_date'],
        )
    )

    if not reward_scheme_details:
        return HttpResponseNotFound()

    response = {
        'scheme_id': reward_scheme_details.scheme_id,
        'description': reward_scheme_details.description,
        'schemes_line_id': reward_scheme_details.schemes_line_id,
        'category': reward_scheme_details.category,
        'food': reward_scheme_details.food,
        'dms': [attr.asdict(option) for option in reward_scheme_details.dms],
        'dms_group': reward_scheme_details.dms_group,
        'bank_cards': reward_scheme_details.bank_cards,
        'name': reward_scheme_details.name,
        'has_food_compensation': reward_scheme_details.has_food_compensation,
        'has_life_insurance': reward_scheme_details.has_life_insurance,
        'has_health_insurance': reward_scheme_details.has_health_insurance,
        'category_changed': False,
        'current_category': None,
    }

    if form.cleaned_data['budget_position_code']:
        current_category = get_schemes_details_usecase.get_current_reward_category(
            budget_position_code=form.cleaned_data['budget_position_code'],
        )
        if current_category:
            response['category_changed'] = reward_scheme_details.category != current_category
            response['current_category'] = current_category

    return JsonResponse(response, status=200)


@auth_by_tvm_only(['femida'])
def check_if_hr_product_changed_view(request: HttpRequest) -> HttpResponse:
    form = CheckIfHrProductChangedForm(data=request.GET)
    if not form.is_valid():
        return JsonResponse(data=form.errors_as_dict(), status=400)

    result = check_if_hr_product_changed_controller(
        form.cleaned_data['budget_position'],
        form.cleaned_data.get('hr_product'),
    )

    return JsonResponse(data=result, status=200)
