"""Advanced metrics service — coverage by tactic, never-tested, avg validation time, detection trend."""

# Enable future language features for compatibility
from __future__ import annotations

# Import datetime, timedelta from datetime
from datetime import datetime, timedelta

# Import case, func from sqlalchemy
from sqlalchemy import case, func

# Import Session from sqlalchemy.orm
from sqlalchemy.orm import Session

# Import TestResult from app.models.enums
from app.models.enums import TestResult

# Import Technique from app.models.technique
from app.models.technique import Technique

# Import Test from app.models.test
from app.models.test import Test


# Define function get_coverage_by_tactic
def get_coverage_by_tactic(db: Session) -> list[dict]:
    """Coverage percentage broken down by MITRE ATT&CK tactic."""
    # Assign results = (
    results = (
        db.query(
            Technique.tactic,
            func.count(Technique.id).label("total"),
            func.sum(
                case((Technique.status_global == "validated", 1), else_=0)
            ).label("validated"),
            func.sum(
                case((Technique.status_global == "partial", 1), else_=0)
            ).label("partial"),
            func.sum(
                case((Technique.status_global == "not_covered", 1), else_=0)
            ).label("not_covered"),
            func.sum(
                case((Technique.status_global == "in_progress", 1), else_=0)
            ).label("in_progress"),
        )
        # Chain .group_by() call
        .group_by(Technique.tactic)
        # Chain .order_by() call
        .order_by(Technique.tactic)
        # Chain .all() call
        .all()
    )
    # Return [
    return [
        {
            # Literal argument value
            "tactic": r[0] or "Unknown",
            # Literal argument value
            "total": r[1],
            # Literal argument value
            "validated": int(r[2]),
            # Literal argument value
            "partial": int(r[3]),
            # Literal argument value
            "not_covered": int(r[4]),
            # Literal argument value
            "in_progress": int(r[5]),
            # Literal argument value
            "coverage_pct": round((int(r[2]) / r[1]) * 100, 1) if r[1] > 0 else 0,
        }
        for r in results
    ]


# Define function get_never_tested_techniques
def get_never_tested_techniques(db: Session) -> list[dict]:
    """Techniques that have never had a test created."""
    # Assign tested_ids = [
    tested_ids = [
        row[0]
        for row in db.query(Test.technique_id)
        # Chain .filter() call
        .filter(Test.technique_id.isnot(None))
        # Chain .distinct() call
        .distinct()
        # Chain .all() call
        .all()
    ]
    # Assign query = db.query(Technique)
    query = db.query(Technique)
    # Check: tested_ids
    if tested_ids:
        # Assign query = query.filter(~Technique.id.in_(tested_ids))
        query = query.filter(~Technique.id.in_(tested_ids))
    # Assign techniques = query.order_by(Technique.mitre_id).all()
    techniques = query.order_by(Technique.mitre_id).all()
    # Return [
    return [
        {
            # Literal argument value
            "mitre_id": t.mitre_id,
            # Literal argument value
            "name": t.name,
            # Literal argument value
            "tactic": t.tactic,
            # Literal argument value
            "is_subtechnique": t.is_subtechnique,
        }
        for t in techniques
    ]


# Define function get_avg_validation_time
def get_avg_validation_time(db: Session) -> dict:
    """Average time from test creation to validation, computed from validated tests.

    Returns overall average and per-phase averages where data is available.
    """
    # Assign validated_tests = (
    validated_tests = (
        db.query(Test)
        # Chain .filter() call
        .filter(Test.state == "validated")
        # Chain .all() call
        .all()
    )

    # Check: not validated_tests
    if not validated_tests:
        # Return {
        return {
            # Literal argument value
            "total_validated": 0,
            # Literal argument value
            "avg_total_hours": 0,
            # Literal argument value
            "avg_red_phase_hours": 0,
            # Literal argument value
            "avg_blue_phase_hours": 0,
        }

    # Assign total_durations = []
    total_durations = []
    # Assign red_durations = []
    red_durations = []
    # Assign blue_durations = []
    blue_durations = []

    # Iterate over validated_tests
    for test in validated_tests:
        # Check: test.created_at and test.red_validated_at
        if test.created_at and test.red_validated_at:
            # Assign total_seconds = (test.red_validated_at - test.created_at).total_seconds()
            total_seconds = (test.red_validated_at - test.created_at).total_seconds()
            # Call total_durations.append()
            total_durations.append(total_seconds)

        # Check: test.red_started_at and test.blue_started_at
        if test.red_started_at and test.blue_started_at:
            # Assign red_sec = (test.blue_started_at - test.red_started_at).total_seconds()
            red_sec = (test.blue_started_at - test.red_started_at).total_seconds()
            # Assign red_paused = test.red_paused_seconds or 0
            red_paused = test.red_paused_seconds or 0
            # Call red_durations.append()
            red_durations.append(max(red_sec - red_paused, 0))

        # Check: test.blue_started_at and test.blue_validated_at
        if test.blue_started_at and test.blue_validated_at:
            # Assign blue_sec = (test.blue_validated_at - test.blue_started_at).total_seconds()
            blue_sec = (test.blue_validated_at - test.blue_started_at).total_seconds()
            # Assign blue_paused = test.blue_paused_seconds or 0
            blue_paused = test.blue_paused_seconds or 0
            # Call blue_durations.append()
            blue_durations.append(max(blue_sec - blue_paused, 0))

    # Define function avg_hours
    def avg_hours(durations: list[float]) -> float:
        # Check: not durations
        if not durations:
            # Return 0
            return 0
        # Return round(sum(durations) / len(durations) / 3600, 2)
        return round(sum(durations) / len(durations) / 3600, 2)

    # Return {
    return {
        # Literal argument value
        "total_validated": len(validated_tests),
        # Literal argument value
        "avg_total_hours": avg_hours(total_durations),
        # Literal argument value
        "avg_red_phase_hours": avg_hours(red_durations),
        # Literal argument value
        "avg_blue_phase_hours": avg_hours(blue_durations),
    }


# Define function get_detection_rate_trend
def get_detection_rate_trend(db: Session) -> list[dict]:
    """Monthly detection rate trend for the last 12 months."""
    # Assign now = datetime.utcnow()
    now = datetime.utcnow()
    # Assign months = []
    months = []

    # Iterate over range(11, -1, -1)
    for i in range(11, -1, -1):
        # Assign month_start = datetime(now.year, now.month, 1) - timedelta(days=i * 30)
        month_start = datetime(now.year, now.month, 1) - timedelta(days=i * 30)
        # Assign month_end = month_start + timedelta(days=30)
        month_end = month_start + timedelta(days=30)

        # Assign validated = (
        validated = (
            db.query(func.count(Test.id))
            # Chain .filter() call
            .filter(
                Test.state == "validated",
                Test.created_at >= month_start,
                Test.created_at < month_end,
            )
            # Chain .scalar() call
            .scalar() or 0
        )

        # Assign detected = (
        detected = (
            db.query(func.count(Test.id))
            # Chain .filter() call
            .filter(
                Test.state == "validated",
                Test.detection_result == TestResult.detected,
                Test.created_at >= month_start,
                Test.created_at < month_end,
            )
            # Chain .scalar() call
            .scalar() or 0
        )

        # Call months.append()
        months.append({
            # Literal argument value
            "month": month_start.strftime("%Y-%m"),
            # Literal argument value
            "validated": validated,
            # Literal argument value
            "detected": detected,
            # Literal argument value
            "detection_rate": round((detected / validated) * 100, 1) if validated > 0 else 0,
        })

    # Return months
    return months
