"""Data aggregation logic for scorecard generation."""

from __future__ import annotations

import logging
from datetime import datetime
from typing import TYPE_CHECKING

from dashboard.services.scorecard.types import TRACKED_AGENTS, AgentMetrics
from dashboard.services.scorecard.validators import (
    extract_actor_from_event,
    is_tracked_agent,
)
from infrastructure.events.bus import get_event_bus

if TYPE_CHECKING:
    from infrastructure.events.bus import Event

logger = logging.getLogger(__name__)


def collect_events_for_period(
    start: datetime, end: datetime, agent_id: str | None = None
) -> list[Event]:
    """Collect events from the event bus for a time period.

    Args:
        start: Period start time
        end: Period end time
        agent_id: Optional agent filter

    Returns:
        List of matching events
    """
    bus = get_event_bus()
    events: list[Event] = []

    # Query persisted events for relevant types
    event_types = [
        "gitea.push",
        "gitea.issue.opened",
        "gitea.issue.comment",
        "gitea.pull_request",
        "agent.task.completed",
        "test.execution",
    ]

    for event_type in event_types:
        try:
            type_events = bus.replay(
                event_type=event_type,
                source=agent_id,
                limit=1000,
            )
            events.extend(type_events)
        except Exception as exc:
            logger.debug("Failed to replay events for %s: %s", event_type, exc)

    # Filter by timestamp
    filtered = []
    for event in events:
        try:
            event_time = datetime.fromisoformat(event.timestamp.replace("Z", "+00:00"))
            if start <= event_time < end:
                filtered.append(event)
        except (ValueError, AttributeError):
            continue

    return filtered


def aggregate_metrics(events: list[Event]) -> dict[str, AgentMetrics]:
    """Aggregate metrics from events grouped by agent.

    Args:
        events: List of events to process

    Returns:
        Dict mapping agent_id -> AgentMetrics
    """
    metrics_by_agent: dict[str, AgentMetrics] = {}

    for event in events:
        actor = extract_actor_from_event(event)

        # Skip non-agent events unless they explicitly have an agent_id
        if not is_tracked_agent(actor) and "agent_id" not in event.data:
            continue

        if actor not in metrics_by_agent:
            metrics_by_agent[actor] = AgentMetrics(agent_id=actor)

        metrics = metrics_by_agent[actor]

        # Process based on event type
        event_type = event.type

        if event_type == "gitea.push":
            metrics.commits += event.data.get("num_commits", 1)

        elif event_type == "gitea.issue.opened":
            issue_num = event.data.get("issue_number", 0)
            if issue_num:
                metrics.issues_touched.add(issue_num)

        elif event_type == "gitea.issue.comment":
            metrics.comments += 1
            issue_num = event.data.get("issue_number", 0)
            if issue_num:
                metrics.issues_touched.add(issue_num)

        elif event_type == "gitea.pull_request":
            pr_num = event.data.get("pr_number", 0)
            action = event.data.get("action", "")
            merged = event.data.get("merged", False)

            if pr_num:
                if action == "opened":
                    metrics.prs_opened.add(pr_num)
                elif action == "closed" and merged:
                    metrics.prs_merged.add(pr_num)
                    # Also count as touched issue for tracking
                    metrics.issues_touched.add(pr_num)

        elif event_type == "agent.task.completed":
            # Extract test files from task data
            affected = event.data.get("tests_affected", [])
            for test in affected:
                metrics.tests_affected.add(test)

            # Token rewards from task completion
            reward = event.data.get("token_reward", 0)
            if reward:
                metrics.tokens_earned += reward

        elif event_type == "test.execution":
            # Track test files that were executed
            test_files = event.data.get("test_files", [])
            for test in test_files:
                metrics.tests_affected.add(test)

    return metrics_by_agent


def query_token_transactions(agent_id: str, start: datetime, end: datetime) -> tuple[int, int]:
    """Query the lightning ledger for token transactions.

    Args:
        agent_id: The agent to query for
        start: Period start
        end: Period end

    Returns:
        Tuple of (tokens_earned, tokens_spent)
    """
    try:
        from lightning.ledger import get_transactions

        transactions = get_transactions(limit=1000)

        earned = 0
        spent = 0

        for tx in transactions:
            # Filter by agent if specified
            if tx.agent_id and tx.agent_id != agent_id:
                continue

            # Filter by timestamp
            try:
                tx_time = datetime.fromisoformat(tx.created_at.replace("Z", "+00:00"))
                if not (start <= tx_time < end):
                    continue
            except (ValueError, AttributeError):
                continue

            if tx.tx_type.value == "incoming":
                earned += tx.amount_sats
            else:
                spent += tx.amount_sats

        return earned, spent

    except Exception as exc:
        logger.debug("Failed to query token transactions: %s", exc)
        return 0, 0


def ensure_all_tracked_agents(
    metrics_by_agent: dict[str, AgentMetrics],
) -> dict[str, AgentMetrics]:
    """Ensure all tracked agents have metrics entries.

    Args:
        metrics_by_agent: Current metrics dictionary

    Returns:
        Updated metrics with all tracked agents included
    """
    for agent_id in TRACKED_AGENTS:
        if agent_id not in metrics_by_agent:
            metrics_by_agent[agent_id] = AgentMetrics(agent_id=agent_id)
    return metrics_by_agent
