"""Metrics API endpoints."""

from uuid import UUID
from decimal import Decimal
from datetime import datetime
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func

from src.api.deps import get_db
from src.repositories.scenario import scenario_repository
from src.schemas.metric import (
    MetricsResponse,
    MetricSummary,
    CostBreakdown,
    TimeseriesPoint,
)
from src.core.exceptions import NotFoundException
from src.services.cost_calculator import cost_calculator
from src.models.scenario_log import ScenarioLog

router = APIRouter()


@router.get("/{scenario_id}/metrics", response_model=MetricsResponse)
async def get_scenario_metrics(scenario_id: UUID, db: AsyncSession = Depends(get_db)):
    """Get aggregated metrics for a scenario."""

    scenario = await scenario_repository.get(db, scenario_id)
    if not scenario:
        raise NotFoundException("Scenario")

    # Get summary metrics
    summary_result = await db.execute(
        select(
            func.count(ScenarioLog.id).label("total_logs"),
            func.sum(ScenarioLog.sqs_blocks).label("total_sqs_blocks"),
            func.sum(ScenarioLog.token_count).label("total_tokens"),
            func.count(ScenarioLog.id)
            .filter(ScenarioLog.has_pii == True)
            .label("pii_violations"),
        ).where(ScenarioLog.scenario_id == scenario_id)
    )
    summary_row = summary_result.one()

    # Calculate costs
    region = scenario.region
    sqs_cost = await cost_calculator.calculate_sqs_cost(
        db, summary_row.total_sqs_blocks or 0, region
    )

    lambda_invocations = (summary_row.total_logs or 0) // 100 + 1
    lambda_cost = await cost_calculator.calculate_lambda_cost(
        db, lambda_invocations, 1.0, region
    )

    bedrock_cost = await cost_calculator.calculate_bedrock_cost(
        db, summary_row.total_tokens or 0, 0, region
    )

    total_cost = sqs_cost + lambda_cost + bedrock_cost

    cost_breakdown = [
        CostBreakdown(
            service="SQS",
            cost_usd=sqs_cost,
            percentage=float(sqs_cost / total_cost * 100) if total_cost > 0 else 0,
        ),
        CostBreakdown(
            service="Lambda",
            cost_usd=lambda_cost,
            percentage=float(lambda_cost / total_cost * 100) if total_cost > 0 else 0,
        ),
        CostBreakdown(
            service="Bedrock",
            cost_usd=bedrock_cost,
            percentage=float(bedrock_cost / total_cost * 100) if total_cost > 0 else 0,
        ),
    ]

    summary = MetricSummary(
        total_requests=scenario.total_requests,
        total_cost_usd=total_cost,
        sqs_blocks=summary_row.total_sqs_blocks or 0,
        lambda_invocations=lambda_invocations,
        llm_tokens=summary_row.total_tokens or 0,
        pii_violations=summary_row.pii_violations or 0,
    )

    # Get timeseries data
    timeseries_result = await db.execute(
        select(
            func.date_trunc("hour", ScenarioLog.received_at).label("hour"),
            func.count(ScenarioLog.id).label("count"),
        )
        .where(ScenarioLog.scenario_id == scenario_id)
        .group_by(func.date_trunc("hour", ScenarioLog.received_at))
        .order_by(func.date_trunc("hour", ScenarioLog.received_at))
    )

    timeseries = [
        TimeseriesPoint(
            timestamp=row.hour, metric_type="requests", value=Decimal(row.count)
        )
        for row in timeseries_result.all()
    ]

    return MetricsResponse(
        scenario_id=scenario_id,
        summary=summary,
        cost_breakdown=cost_breakdown,
        timeseries=timeseries,
    )
