"""Statistical analysis of SCP impact."""

from collections import Counter, defaultdict
from datetime import datetime, timedelta

from ..engine.matcher import extract_service
from ..models.cloudtrail import CloudTrailEvent
from ..models.report import EvaluationResult, ImpactStatistics

# Critical AWS services that affect security/operations
CRITICAL_SERVICES = {
    "iam",
    "sts",
    "kms",
    "cloudtrail",
    "config",
    "guardduty",
    "securityhub",
    "organizations",
    "cloudformation",
    "lambda",
}


def calculate_statistics(
    denied_events: list[tuple[CloudTrailEvent, EvaluationResult]],
    analysis_period: tuple[datetime, datetime],
    all_results: list[EvaluationResult] | None = None,
) -> ImpactStatistics:
    """
    Calculate comprehensive statistics from denied events.

    Args:
        denied_events: List of (event, result) tuples for denied events
        analysis_period: (start_time, end_time) tuple for analysis
        all_results: Optional list of all evaluation results (for confidence metrics)

    Returns:
        ImpactStatistics object with detailed analysis
    """
    stats = ImpactStatistics()

    # Calculate simulation confidence metrics from all results
    if all_results:
        stats.total_evaluated_events = len(all_results)
        unevaluable_counter: Counter[str] = Counter()
        unresolved_count = 0

        for result in all_results:
            # Count unevaluable condition keys
            for key in result.unevaluable_condition_keys:
                unevaluable_counter[key] += 1
            # Count unresolved resources
            if not result.resource_arn_resolved:
                unresolved_count += 1

        stats.unevaluable_keys_summary = dict(unevaluable_counter)
        stats.unresolved_resource_count = unresolved_count

    if not denied_events:
        return stats  # Return empty statistics (but with confidence metrics)

    # Extract events and results
    events = [event for event, _ in denied_events]
    results = [result for _, result in denied_events]

    # Calculate denials by service
    service_counter: Counter[str] = Counter()
    for event in events:
        service = extract_service(event.iam_action)
        service_counter[service] += 1
    stats.denied_by_service = dict(service_counter)

    # Calculate top denied actions
    action_counter: Counter[str] = Counter()
    for event in events:
        action_counter[event.iam_action] += 1
    stats.top_denied_actions = action_counter.most_common()

    # Calculate affected principals
    principal_counter: Counter[str] = Counter()
    for event in events:
        if event.principal_arn:
            principal_counter[event.principal_arn] += 1
    stats.affected_principals = dict(principal_counter)

    # Calculate denials by statement
    statement_counter: Counter[str] = Counter()
    for result in results:
        if result.matched_statement and result.matched_statement.sid:
            statement_counter[result.matched_statement.sid] += 1
        elif result.matched_statement:
            # Use first action as identifier if no SID
            action = (
                result.matched_statement.actions[0]
                if result.matched_statement.actions
                else "Unknown"
            )
            statement_counter[f"Statement ({action})"] += 1
    stats.denials_by_statement = dict(statement_counter)

    # Calculate denials over time (bucketed by day)
    stats.denials_over_time = _calculate_time_series(events, analysis_period)

    # Identify critical services affected
    stats.critical_services_affected = [
        service for service in stats.denied_by_service.keys() if service in CRITICAL_SERVICES
    ]

    # Calculate production impact score (0-100)
    stats.production_impact_score = _calculate_impact_score(
        denied_count=len(denied_events),
        critical_services=stats.critical_services_affected,
        top_actions=stats.top_denied_actions,
    )

    return stats


def _calculate_time_series(
    events: list[CloudTrailEvent],
    analysis_period: tuple[datetime, datetime],
) -> list[tuple[datetime, int]]:
    """
    Calculate denials over time, bucketed by day.

    Args:
        events: List of denied CloudTrail events
        analysis_period: (start_time, end_time) for analysis

    Returns:
        List of (datetime, count) tuples for each day
    """
    start_time, end_time = analysis_period

    # Count denials by day
    denials_by_day: defaultdict[datetime, int] = defaultdict(int)
    for event in events:
        # Normalize to start of day
        day = event.event_time.replace(hour=0, minute=0, second=0, microsecond=0)
        denials_by_day[day] += 1

    # Create full time series (including days with 0 denials)
    time_series: list[tuple[datetime, int]] = []
    current_day = start_time.replace(hour=0, minute=0, second=0, microsecond=0)
    end_day = end_time.replace(hour=0, minute=0, second=0, microsecond=0)

    while current_day <= end_day:
        count = denials_by_day.get(current_day, 0)
        time_series.append((current_day, count))
        current_day += timedelta(days=1)

    return time_series


def _calculate_impact_score(
    denied_count: int,
    critical_services: list[str],
    top_actions: list[tuple[str, int]],
) -> float:
    """
    Calculate a production impact score (0-100).

    Factors:
    - Number of denials (volume)
    - Critical services affected
    - Concentration of denials (few actions vs many)

    Args:
        denied_count: Total number of denied events
        critical_services: List of critical services affected
        top_actions: List of (action, count) tuples

    Returns:
        Impact score from 0-100
    """
    score = 0.0

    # Factor 1: Volume of denials (0-40 points)
    # Log scale: 1 denial = ~5 points, 100 = ~20, 1000+ = ~40
    if denied_count > 0:
        import math

        volume_score = min(40.0, 10.0 * math.log10(denied_count + 1))
        score += volume_score

    # Factor 2: Critical services (0-30 points)
    # Each critical service adds points
    critical_score = min(30.0, len(critical_services) * 10.0)
    score += critical_score

    # Factor 3: Concentration (0-30 points)
    # If denials are concentrated in a few actions, impact is higher
    if top_actions and denied_count > 0:
        # If top action accounts for >50% of denials, high concentration
        top_action_count = top_actions[0][1]
        concentration_ratio = top_action_count / denied_count
        if concentration_ratio > 0.5:
            score += 30.0 * concentration_ratio
        else:
            score += 15.0

    return min(100.0, score)
