from typing import List, Optional

import attr

from django.db.models import QuerySet
from django.http import HttpRequest, HttpResponse, JsonResponse, HttpResponseForbidden
from django.views.decorators.http import require_GET
from django.utils.translation import get_language

from staff.budget_position.models import BudgetPositionAssignment
from staff.departments.models import Department, InstanceClass, RelevanceDate
from staff.lib.xlsx import make_xlsx_file_response

from staff.headcounts.forms import BudgetPositionAssignmentGroupingAndFiltersForm
from staff.headcounts.headcounts_summary.assignments_page_model import AssignmentsPageModel
from staff.headcounts.headcounts_summary.assignments_sheet_presenter import AssignmentsSheetPresenter
from staff.headcounts.headcounts_summary.export_summary_model import export_summary_model
from staff.headcounts.headcounts_summary.headcounts_summary_calculator_new import HeadcountsSummaryCalculator
from staff.headcounts.headcounts_summary.query_builder import (
    HierarchyValues,
    QueryBuilder,
    QueryParams,
)
from staff.headcounts.headcounts_summary.summary_sheet_presenter import SummarySheetPresenter
from staff.headcounts.headcounts_export import RU_HELP_PAGE_MODEL, EN_HELP_PAGE_MODEL, HelpPagePresenter
from staff.headcounts.permissions import Permissions


class QueryParamsPermissionsCalculator:
    def __init__(self, permissions: Permissions) -> None:
        self.permissions = permissions
        self._has_special_role_cache: Optional[bool] = None
        self._departments_with_headcount_permission_cache: Optional[QuerySet] = None

    @property
    def _has_special_role(self) -> bool:
        if self._has_special_role_cache is None:
            self._has_special_role_cache = self.permissions.has_special_role()
        return self._has_special_role_cache

    @property
    def _departments_with_headcount_permission(self) -> List[Department]:
        if self._departments_with_headcount_permission_cache is None:
            self._departments_with_headcount_permission_cache = list(
                self.permissions.departments_with_headcount_permission()
            )
        return self._departments_with_headcount_permission_cache

    def department_instance_filters(self, instance_class: InstanceClass) -> List[HierarchyValues]:
        if self.permissions.has_special_role():
            return []

        result = [
            HierarchyValues(tree_id=department.tree_id, lft=department.lft, rght=department.rght, id=department.id)
            for department in self.permissions.departments_with_headcount_permission()
            if department.instance_class == instance_class.value
        ]
        return result or [HierarchyValues.none()]


def create_summary_calculator(
    form: BudgetPositionAssignmentGroupingAndFiltersForm,
    permissions: Permissions,
) -> HeadcountsSummaryCalculator:
    filters_calculator = QueryParamsPermissionsCalculator(permissions)

    params = QueryParams(
        groupings=form.cleaned_data['groupings'],
        department_filters=form.cleaned_data['department_filters'],
        value_stream_filters=form.cleaned_data['value_stream_filters'],
        geography_filters=form.cleaned_data['geography_filters'],
        department_permission_filters=filters_calculator.department_instance_filters(InstanceClass.DEPARTMENT),
        value_stream_permission_filters=filters_calculator.department_instance_filters(InstanceClass.VALUESTREAM),
        geography_permission_filters=filters_calculator.department_instance_filters(InstanceClass.GEOGRAPHY),
        enable_hierarchy_filter=not form.is_debug(),
        enable_empty_summary_filter=not form.is_debug(),
        summary_with_child=not form.is_debug(),
    )
    query_builder = QueryBuilder(params)
    return HeadcountsSummaryCalculator(query_builder)


@require_GET
def summary(request: HttpRequest) -> HttpResponse:
    permissions = Permissions(request.user.get_profile())

    if not permissions.has_management_options():
        return HttpResponseForbidden()

    form = BudgetPositionAssignmentGroupingAndFiltersForm.from_query_dict(request.GET)
    if not form.is_valid():
        return JsonResponse(form.errors, status=400)
    summary_calculator = create_summary_calculator(form, permissions)
    results = summary_calculator.get_results()
    result_as_dict = attr.asdict(results) if results else {}
    if form.is_debug():
        result_as_dict['debug'] = summary_export.debug_summary()

    return JsonResponse(result_as_dict)


@require_GET
def summary_export(request: HttpRequest) -> HttpResponse:
    permissions = Permissions(request.user.get_profile())

    if not permissions.has_management_options():
        return HttpResponseForbidden()

    form = BudgetPositionAssignmentGroupingAndFiltersForm.from_query_dict(request.GET)
    if not form.is_valid():
        return JsonResponse(form.errors, status=400)

    summary_calculator = create_summary_calculator(form, permissions)
    data_model = export_summary_model(
        summary_calculator.get_results(),
        summary_calculator.query_params.groupings,
    )
    assignments_model = AssignmentsPageModel(summary_calculator.query_params)

    pages = [
        SummarySheetPresenter(data_model, summary_calculator.query_params.groupings, get_language()),
        AssignmentsSheetPresenter(assignments_model.get_result(), get_language()),
        HelpPagePresenter(EN_HELP_PAGE_MODEL if get_language() == 'en' else RU_HELP_PAGE_MODEL),
    ]

    relevance_date = RelevanceDate.objects.get(model_name=BudgetPositionAssignment.__name__).relevance_date
    file_name = f'ceilings_updated_on_{relevance_date}'
    return make_xlsx_file_response(pages, file_name)
