from __future__ import annotations

import json
from datetime import datetime
from typing import Any, Dict, Optional

from sqlalchemy.orm import Session

from models.performance_metric import PerformanceMetric


class MetricsService:
    def __init__(self, db: Session):
        self.db = db

    def store_metric(
        self,
        metric_name: str,
        value: float,
        labels: Optional[Dict[str, Any]] = None,
        endpoint: Optional[str] = None,
        method: Optional[str] = None,
        status_code: Optional[int] = None,
        duration_seconds: Optional[float] = None,
    ) -> PerformanceMetric:
        """Store a performance metric in the database."""
        metric = PerformanceMetric(
            timestamp=datetime.utcnow(),
            metric_name=metric_name,
            value=value,
            labels=json.dumps(labels) if labels else None,
            endpoint=endpoint,
            method=method,
            status_code=status_code,
            duration_seconds=duration_seconds,
        )
        self.db.add(metric)
        self.db.commit()
        self.db.refresh(metric)
        return metric

    def get_metrics(
        self,
        metric_name: Optional[str] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        limit: int = 100,
    ) -> list[PerformanceMetric]:
        """Retrieve stored metrics with optional filtering."""
        query = self.db.query(PerformanceMetric)

        if metric_name:
            query = query.filter(PerformanceMetric.metric_name == metric_name)

        if start_time:
            query = query.filter(PerformanceMetric.timestamp >= start_time)

        if end_time:
            query = query.filter(PerformanceMetric.timestamp <= end_time)

        return query.order_by(PerformanceMetric.timestamp.desc()).limit(limit).all()

    def get_aggregated_metrics(
        self,
        metric_name: str,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
    ) -> Dict[str, Any]:
        """Get aggregated statistics for a metric."""
        query = self.db.query(PerformanceMetric).filter(
            PerformanceMetric.metric_name == metric_name
        )

        if start_time:
            query = query.filter(PerformanceMetric.timestamp >= start_time)

        if end_time:
            query = query.filter(PerformanceMetric.timestamp <= end_time)

        metrics = query.all()

        if not metrics:
            return {"count": 0, "avg": 0, "min": 0, "max": 0}

        values = [m.value for m in metrics]
        return {
            "count": len(values),
            "avg": sum(values) / len(values),
            "min": min(values),
            "max": max(values),
        }


def get_metrics_service(db: Session) -> MetricsService:
    return MetricsService(db)
