from xml.etree import ElementTree

import requests
from django.conf import settings
from django.core.paginator import Paginator
from django.db import models
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render
from django_downloadview import ObjectDownloadView
from django_http_exceptions import HTTPExceptions
from guardian.shortcuts import get_objects_for_user

from .models import Contract, ContractFile


class ContractFileDownloadView(ObjectDownloadView):
    model = ContractFile
    file_field = "file"
    attachment = False

    def get_queryset(self, *args, **kwargs):
        queryset = super().get_queryset(*args, **kwargs)

        if not self.current_user.has_perm("contracts.view_confidential"):
            queryset = queryset.filter(is_public=True)

        return queryset

    def get(self, request, *args, **kwargs):
        self.current_user = request.user

        return super().get(request, *args, **kwargs)


def get_base_context(request) -> dict:
    return {
        "site_url": settings.SITE_URL,
        "user": request.user,
    }


def get_pagination(request, objects) -> tuple:
    paginator = Paginator(objects, 25)

    page = paginator.get_page(request.GET.get("page"))

    return page, paginator


def get_paginated_contracts(request, filter=None) -> tuple:
    if filter is None:
        filter = models.Q()

    filter = models.Q(is_approved=True)

    if not request.user.has_perm("contracts.view_confidential"):
        additional_filter = models.Q(is_public=True)

        if not request.user.is_anonymous:
            additional_filter = additional_filter | models.Q(created_by=request.user)

        filter = filter & additional_filter

    contracts = (
        get_objects_for_user(request.user, "contracts.view_contract")
        .filter(filter)
        .order_by("valid_start_date")
        .all()
    )

    page, paginator = get_pagination(request, contracts)

    return page, paginator


def index(request):
    page, paginator = get_paginated_contracts(request)

    return render(
        request,
        "contracts/index.html",
        {
            **get_base_context(request),
            "title": "Seznam smluv",
            "description": "Description",
            "page": page,
            "paginator": paginator,
        },
    )


def view_contract(request, id: int):
    filter = models.Q(is_approved=True)

    if not request.user.has_perm("contracts.view_confidential"):
        filter = filter & (
            models.Q(is_public=True)
            | (
                models.Q(created_by=request.user)
                if not request.user.is_anonymous
                else models.Value(True)
            )
        )

    contract = get_object_or_404(
        (get_objects_for_user(request.user, "contracts.view_contract").filter(filter)),
        id=id,
    )

    return render(
        request,
        "contracts/view_contract.html",
        {
            **get_base_context(request),
            "title": contract.name,
            "description": contract.summary,
            "contract": contract,
        },
    )


def search(request):
    query = request.GET.get("q")
    page = paginator = None
    title = "Vyhledávání"

    if query is not None:
        title = f"Vyhledávání - {query}"

        # WARNING: PostgreSQL-dependent
        page, paginator = get_paginated_contracts(
            request,
            models.Q(name__search=query)
        )

    return render(
        "contracts/search.html",
        {
            **get_base_context(request),
            "title": title,
            "description": "Vyhledávání smluv v registru České Pirátské Strany.",
            "page": page,
            "paginator": paginator,
            "query": query,
        }
    )


# BEGIN Filtered contract + submodel views


def view_contract_filing_area(request, id: int):
    filing_area = get_object_or_404(
        get_objects_for_user(request.user, "contracts.view_contractfilingarea"), id=id
    )

    contracts_page, contracts_paginator = get_paginated_contracts(
        request, models.Q(filing_area=filing_area)
    )

    return render(
        request,
        "contracts/view_contract_filing_area.html",
        {
            **get_base_context(request),
            "title": filing_area.name,
            "description": (
                f"Spisovna smluv - {filing_area.name}, "
                f"zodpovědná osoba {filing_area.person_responsible}"
            ),
            "filing_area": filing_area,
            "contracts_page": contracts_page,
            "contracts_paginator": contracts_paginator,
        },
    )


def view_contract_issue(request, id: int):
    issue = get_object_or_404(
        get_objects_for_user(request.user, "contracts.view_contractissue"), id=id
    )

    contracts_page, contracts_paginator = get_paginated_contracts(
        request, models.Q(issues=issue)
    )

    return render(
        request,
        "contracts/view_contract_issue.html",
        {
            **get_base_context(request),
            "title": issue.name,
            "description": f"Problém se smlouvami - {issue.name}",
            "issue": issue,
            "contracts_page": contracts_page,
            "contracts_paginator": contracts_paginator,
        },
    )


def view_contract_type(request, id: int):
    type_ = get_object_or_404(
        get_objects_for_user(request.user, "contracts.view_contracttype"), id=id
    )

    contracts_page, contracts_paginator = get_paginated_contracts(
        request, models.Q(types=type_)
    )

    return render(
        request,
        "contracts/view_contract_type.html",
        {
            **get_base_context(request),
            "title": type_.name,
            "description": f"Typ smluv - {type_.name}",
            "type": type_,
            "contracts_page": contracts_page,
            "contracts_paginator": contracts_paginator,
        },
    )


def view_contractee(request, id: int):
    contractee = get_object_or_404(
        get_objects_for_user(request.user, "contracts.view_contractee"), id=id
    )

    contracts_page, contracts_paginator = get_paginated_contracts(
        request, models.Q(contractee_signatures__contractee=contractee)
    )

    return render(
        request,
        "contracts/view_contractee.html",
        {
            **get_base_context(request),
            "title": contractee.name,
            "description": f"Naše smluvní strana - {contractee.name}",
            "contractee": contractee,
            "contracts_page": contracts_page,
            "contracts_paginator": contracts_paginator,
        },
    )


def view_signee(request, id: int):
    signee = get_object_or_404(
        get_objects_for_user(request.user, "contracts.view_signee"), id=id
    )

    contracts_page, contracts_paginator = get_paginated_contracts(
        request, models.Q(signee_signatures__signee=signee)
    )

    return render(
        request,
        "contracts/view_signee.html",
        {
            **get_base_context(request),
            "title": signee.name,
            "description": f"Jiná smluvní strana - {signee.name}",
            "signee": signee,
            "contracts_page": contracts_page,
            "contracts_paginator": contracts_paginator,
        },
    )


# END Filtered contract + submodel views

# BEGIN Submodel listing views


def view_contract_filing_areas(request):
    filing_areas = get_objects_for_user(
        request.user,
        "contracts.view_contractfilingarea",
    ).order_by("name")

    page, paginator = get_pagination(request, filing_areas)

    return render(
        request,
        "contracts/view_contract_filing_areas.html",
        {
            **get_base_context(request),
            "title": "Spisovny",
            "description": "Seznam fyzických spisoven, kde jsou ukládány smlouvy.",
            "page": page,
            "paginator": paginator,
        },
    )


def view_contract_issues(request):
    issues = get_objects_for_user(
        request.user,
        "contracts.view_contractissue",
    ).order_by("name")

    page, paginator = get_pagination(request, issues)

    return render(
        request,
        "contracts/view_contract_issues.html",
        {
            **get_base_context(request),
            "title": (
                "Poznámky"
                if (request.user.is_anonymous or not request.user.can_view_confidential)
                else "Problémy"
            ),
            "description": (
                "Poznámky ke smlouvám."
                if (request.user.is_anonymous or not request.user.can_view_confidential)
                else "Problémy se smlouvami."
            ),
            "page": page,
            "paginator": paginator,
        },
    )


def view_contract_types(request):
    types = get_objects_for_user(
        request.user,
        "contracts.view_contracttype",
    ).order_by("name")

    page, paginator = get_pagination(request, types)

    return render(
        request,
        "contracts/view_contract_types.html",
        {
            **get_base_context(request),
            "title": "Typy",
            "description": "Typy smluv.",
            "page": page,
            "paginator": paginator,
        },
    )


def view_contractees(request):
    contractees = get_objects_for_user(
        request.user,
        "contracts.view_contractee",
    ).order_by("name")

    page, paginator = get_pagination(request, contractees)

    return render(
        request,
        "contracts/view_contractees.html",
        {
            **get_base_context(request),
            "title": "Naše smluvní strany",
            "description": "Naše smluvní strany.",
            "page": page,
            "paginator": paginator,
        },
    )


def view_signees(request):
    contractees = get_objects_for_user(
        request.user,
        "contracts.view_signee",
    ).order_by("name")

    page, paginator = get_pagination(request, contractees)

    return render(
        request,
        "contracts/view_signees.html",
        {
            **get_base_context(request),
            "title": "Jiné smluvní strany",
            "description": "Jiné smluvní strany.",
            "page": page,
            "paginator": paginator,
        },
    )


# END Submodel listing views


# ARES CORS proxy
def get_ares_info(request, ico: int):
    if not request.user.is_staff:
        raise HTTPExceptions.FORBIDDEN

    ares_info = requests.get(
        f"https://wwwinfo.mfcr.cz/cgi-bin/ares/darv_std.cgi?ico={ico}"
    )

    tree = ElementTree.fromstring(ares_info.content)

    for result_count in tree.iter("are:Pocet_zaznamu"):
        if result_count.text == "0":
            raise HTTPExceptions.NOT_FOUND

    return HttpResponse(
        content=ares_info.content,
        status=ares_info.status_code,
        content_type=ares_info.headers.get("Content-Type"),
    )