# mypy: ignore-errors

from datetime import datetime, timedelta

from flask import Blueprint, render_template
from flask.typing import ResponseReturnValue
from sqlalchemy import func, and_, desc
from sqlalchemy.orm import aliased

from app.extensions import db
from app.models import Deprecation
from app.models.mirrors import Proxy, Origin, Country

report = Blueprint("report", __name__)


def generate_subqueries():
    DeprecationAlias = aliased(Deprecation)
    now = datetime.utcnow()
    deprecations_24hr_subquery = (
        db.session.query(
            DeprecationAlias.resource_id,
            func.count(DeprecationAlias.resource_id).label('deprecations_24hr')
        )
        .filter(
            DeprecationAlias.reason.like('block_%'),
            DeprecationAlias.deprecated_at >= now - timedelta(hours=24),
            DeprecationAlias.resource_type == 'Proxy'
        )
        .group_by(DeprecationAlias.resource_id)
        .subquery()
    )
    deprecations_72hr_subquery = (
        db.session.query(
            DeprecationAlias.resource_id,
            func.count(DeprecationAlias.resource_id).label('deprecations_72hr')
        )
        .filter(
            DeprecationAlias.reason.like('block_%'),
            DeprecationAlias.deprecated_at >= now - timedelta(hours=72),
            DeprecationAlias.resource_type == 'Proxy'
        )
        .group_by(DeprecationAlias.resource_id)
        .subquery()
    )
    return deprecations_24hr_subquery, deprecations_72hr_subquery


def countries_report():
    deprecations_24hr_subquery, deprecations_72hr_subquery = generate_subqueries()

    return (
        db.session.query(
            Country,
            func.coalesce(func.sum(deprecations_24hr_subquery.c.deprecations_24hr), 0).label('total_deprecations_24hr'),
            func.coalesce(func.sum(deprecations_72hr_subquery.c.deprecations_72hr), 0).label('total_deprecations_72hr')
        )
        .join(Origin, Country.origins)
        .join(Proxy, Origin.proxies)
        .outerjoin(deprecations_24hr_subquery, Proxy.id == deprecations_24hr_subquery.c.resource_id)
        .outerjoin(deprecations_72hr_subquery, Proxy.id == deprecations_72hr_subquery.c.resource_id)
        .group_by(Country.id)
        .all()
    )


def origins_report():
    deprecations_24hr_subquery, deprecations_72hr_subquery = generate_subqueries()

    return (
        db.session.query(
            Origin,
            func.coalesce(func.sum(deprecations_24hr_subquery.c.deprecations_24hr), 0).label('total_deprecations_24hr'),
            func.coalesce(func.sum(deprecations_72hr_subquery.c.deprecations_72hr), 0).label('total_deprecations_72hr')
        )
        .outerjoin(Proxy, Origin.proxies)
        .outerjoin(deprecations_24hr_subquery, Proxy.id == deprecations_24hr_subquery.c.resource_id)
        .outerjoin(deprecations_72hr_subquery, Proxy.id == deprecations_72hr_subquery.c.resource_id)
        .filter(Origin.destroyed.is_(None))
        .group_by(Origin.id)
        .order_by(desc("total_deprecations_24hr"))
        .all()
    )


@report.app_template_filter('country_name')
def country_description_filter(country_code):
    country = Country.query.filter_by(country_code=country_code).first()
    return country.description if country else None


@report.route("/blocks", methods=['GET'])
def report_blocks() -> ResponseReturnValue:
    blocked_today = db.session.query(  # type: ignore[no-untyped-call]
        Origin.domain_name,
        Origin.description,
        Proxy.added,
        Proxy.deprecated,
        Proxy.deprecation_reason
    ).join(Origin, Origin.id == Proxy.origin_id
           ).filter(and_(Proxy.deprecated > datetime.utcnow() - timedelta(days=1),
                         Proxy.deprecation_reason.like('block_%'))).all()

    return render_template("report_blocks.html.j2",
                           blocked_today=blocked_today,
                           origins=sorted(origins_report(), key=lambda o: o[1], reverse=True),
                           countries=sorted(countries_report(), key=lambda c: c[0].risk_level, reverse=True),
                           )
