"""Routes for metrics dashboard."""

from datetime import datetime, timedelta

from flask import Blueprint, jsonify, request
from loguru import logger
from sqlalchemy import case, func

from ...metrics import TokenCounter
from ...metrics.db_models import ResearchRating, TokenUsage
from ...metrics.query_utils import get_time_filter_condition
from ...metrics.search_tracker import get_search_tracker
from ...utilities.db_utils import get_db_session
from ..database.models import Research, ResearchStrategy
from ..utils.templates import render_template_with_defaults

# Create a Blueprint for metrics
metrics_bp = Blueprint("metrics", __name__, url_prefix="/metrics")


def get_rating_analytics(period="30d", research_mode="all"):
    """Get rating analytics for the specified period and research mode."""
    try:
        from ...metrics.database import get_metrics_db
        from ...metrics.db_models import ResearchRating

        db = get_metrics_db()

        # Calculate date range
        days_map = {"7d": 7, "30d": 30, "90d": 90, "365d": 365, "all": None}

        days = days_map.get(period, 30)

        with db.get_session() as session:
            query = session.query(ResearchRating)

            # Apply time filter
            if days:
                cutoff_date = datetime.now() - timedelta(days=days)
                query = query.filter(ResearchRating.rated_at >= cutoff_date)

            # Get all ratings
            ratings = query.all()

            if not ratings:
                return {
                    "rating_analytics": {
                        "avg_rating": None,
                        "total_ratings": 0,
                        "rating_distribution": {},
                        "satisfaction_stats": {
                            "very_satisfied": 0,  # 5 stars
                            "satisfied": 0,  # 4 stars
                            "neutral": 0,  # 3 stars
                            "dissatisfied": 0,  # 2 stars
                            "very_dissatisfied": 0,  # 1 star
                        },
                    }
                }

            # Calculate statistics
            rating_values = [r.rating for r in ratings]
            avg_rating = sum(rating_values) / len(rating_values)

            # Rating distribution
            rating_counts = {}
            for i in range(1, 6):
                rating_counts[str(i)] = rating_values.count(i)

            # Satisfaction categories
            satisfaction_stats = {
                "very_satisfied": rating_values.count(5),
                "satisfied": rating_values.count(4),
                "neutral": rating_values.count(3),
                "dissatisfied": rating_values.count(2),
                "very_dissatisfied": rating_values.count(1),
            }

            return {
                "rating_analytics": {
                    "avg_rating": round(avg_rating, 1),
                    "total_ratings": len(ratings),
                    "rating_distribution": rating_counts,
                    "satisfaction_stats": satisfaction_stats,
                }
            }

    except Exception as e:
        logger.exception(f"Error getting rating analytics: {e}")
        return {
            "rating_analytics": {
                "avg_rating": None,
                "total_ratings": 0,
                "rating_distribution": {},
                "satisfaction_stats": {
                    "very_satisfied": 0,
                    "satisfied": 0,
                    "neutral": 0,
                    "dissatisfied": 0,
                    "very_dissatisfied": 0,
                },
            }
        }


def get_available_strategies():
    """Get list of all available search strategies from the search system."""
    # This list comes from the AdvancedSearchSystem.__init__ method
    strategies = [
        {"name": "standard", "description": "Basic iterative search strategy"},
        {
            "name": "iterdrag",
            "description": "Iterative Dense Retrieval Augmented Generation",
        },
        {
            "name": "source-based",
            "description": "Focuses on finding and extracting from sources",
        },
        {
            "name": "parallel",
            "description": "Runs multiple search queries in parallel",
        },
        {"name": "rapid", "description": "Quick single-pass search"},
        {
            "name": "recursive",
            "description": "Recursive decomposition of complex queries",
        },
        {
            "name": "iterative",
            "description": "Loop-based reasoning with persistent knowledge",
        },
        {"name": "adaptive", "description": "Adaptive step-by-step reasoning"},
        {
            "name": "smart",
            "description": "Automatically chooses best strategy based on query",
        },
        {
            "name": "browsecomp",
            "description": "Optimized for BrowseComp-style puzzle queries",
        },
        {
            "name": "evidence",
            "description": "Enhanced evidence-based verification with improved candidate discovery",
        },
        {
            "name": "constrained",
            "description": "Progressive constraint-based search that narrows candidates step by step",
        },
        {
            "name": "parallel-constrained",
            "description": "Parallel constraint-based search with combined constraint execution",
        },
        {
            "name": "early-stop-constrained",
            "description": "Parallel constraint search with immediate evaluation and early stopping at 99% confidence",
        },
        {
            "name": "smart-query",
            "description": "Smart query generation strategy",
        },
        {
            "name": "dual-confidence",
            "description": "Dual confidence scoring with positive/negative/uncertainty",
        },
        {
            "name": "dual-confidence-with-rejection",
            "description": "Dual confidence with early rejection of poor candidates",
        },
        {
            "name": "concurrent-dual-confidence",
            "description": "Concurrent search & evaluation with progressive constraint relaxation",
        },
        {
            "name": "modular",
            "description": "Modular architecture using constraint checking and candidate exploration modules",
        },
        {
            "name": "modular-parallel",
            "description": "Modular strategy with parallel exploration",
        },
        {
            "name": "focused-iteration",
            "description": "Focused iteration strategy optimized for accuracy",
        },
        {
            "name": "browsecomp-entity",
            "description": "Entity-focused search for BrowseComp questions with knowledge graph building",
        },
    ]
    return strategies


def get_strategy_analytics(period="30d"):
    """Get strategy usage analytics for the specified period."""
    try:
        # Calculate date range
        days_map = {"7d": 7, "30d": 30, "90d": 90, "365d": 365, "all": None}
        days = days_map.get(period, 30)

        session = get_db_session()

        try:
            # Check if we have any ResearchStrategy records
            strategy_count = session.query(ResearchStrategy).count()

            if strategy_count == 0:
                logger.warning("No research strategies found in database")
                return {
                    "strategy_analytics": {
                        "total_research_with_strategy": 0,
                        "total_research": 0,
                        "most_popular_strategy": None,
                        "strategy_usage": [],
                        "strategy_distribution": {},
                        "available_strategies": get_available_strategies(),
                        "message": "Strategy tracking not yet available - run a research to start tracking",
                    }
                }

            # Base query for strategy usage (no JOIN needed since we just want strategy counts)
            query = session.query(
                ResearchStrategy.strategy_name,
                func.count(ResearchStrategy.id).label("usage_count"),
            )

            # Apply time filter if specified
            if days:
                cutoff_date = datetime.now() - timedelta(days=days)
                query = query.filter(ResearchStrategy.created_at >= cutoff_date)

            # Group by strategy and order by usage
            strategy_results = (
                query.group_by(ResearchStrategy.strategy_name)
                .order_by(func.count(ResearchStrategy.id).desc())
                .all()
            )

            # Get total strategy count for percentage calculation
            total_query = session.query(ResearchStrategy)
            if days:
                total_query = total_query.filter(
                    ResearchStrategy.created_at >= cutoff_date
                )
            total_research = total_query.count()

        finally:
            session.close()

        # Format strategy data
        strategy_usage = []
        strategy_distribution = {}

        for strategy_name, usage_count in strategy_results:
            percentage = (
                (usage_count / total_research * 100)
                if total_research > 0
                else 0
            )
            strategy_usage.append(
                {
                    "strategy": strategy_name,
                    "count": usage_count,
                    "percentage": round(percentage, 1),
                }
            )
            strategy_distribution[strategy_name] = usage_count

        # Find most popular strategy
        most_popular = strategy_usage[0]["strategy"] if strategy_usage else None

        return {
            "strategy_analytics": {
                "total_research_with_strategy": sum(
                    item["count"] for item in strategy_usage
                ),
                "total_research": total_research,
                "most_popular_strategy": most_popular,
                "strategy_usage": strategy_usage,
                "strategy_distribution": strategy_distribution,
                "available_strategies": get_available_strategies(),
            }
        }

    except Exception as e:
        logger.exception(f"Error getting strategy analytics: {e}")
        return {
            "strategy_analytics": {
                "total_research_with_strategy": 0,
                "total_research": 0,
                "most_popular_strategy": None,
                "strategy_usage": [],
                "strategy_distribution": {},
                "available_strategies": get_available_strategies(),
                "error": str(e),
            }
        }


@metrics_bp.route("/")
def metrics_dashboard():
    """Render the metrics dashboard page."""
    return render_template_with_defaults("pages/metrics.html")


@metrics_bp.route("/api/metrics")
def api_metrics():
    """Get overall metrics data."""
    try:
        # Get time period and research mode from query parameters
        period = request.args.get("period", "30d")
        research_mode = request.args.get("mode", "all")

        token_counter = TokenCounter()
        search_tracker = get_search_tracker()

        # Get both token and search metrics
        token_metrics = token_counter.get_overall_metrics(
            period=period, research_mode=research_mode
        )
        search_metrics = search_tracker.get_search_metrics(
            period=period, research_mode=research_mode
        )

        # Get user satisfaction rating data
        try:
            from sqlalchemy import func

            from ...metrics.db_models import ResearchRating

            with get_db_session() as session:
                # Build base query with time filter
                ratings_query = session.query(ResearchRating)
                time_condition = get_time_filter_condition(
                    period, ResearchRating.rated_at
                )
                if time_condition is not None:
                    ratings_query = ratings_query.filter(time_condition)

                # Get average rating
                avg_rating = ratings_query.with_entities(
                    func.avg(ResearchRating.rating).label("avg_rating")
                ).scalar()

                # Get total rating count
                total_ratings = ratings_query.count()

                user_satisfaction = {
                    "avg_rating": round(avg_rating, 1) if avg_rating else None,
                    "total_ratings": total_ratings,
                }
        except Exception as e:
            logger.warning(f"Error getting user satisfaction data: {e}")
            user_satisfaction = {"avg_rating": None, "total_ratings": 0}

        # Get strategy analytics
        strategy_data = get_strategy_analytics(period)

        # Combine metrics
        combined_metrics = {
            **token_metrics,
            **search_metrics,
            **strategy_data,
            "user_satisfaction": user_satisfaction,
        }

        return jsonify(
            {
                "status": "success",
                "metrics": combined_metrics,
                "period": period,
                "research_mode": research_mode,
            }
        )
    except Exception as e:
        logger.exception(f"Error getting metrics: {e}")
        return (
            jsonify(
                {
                    "status": "error",
                    "message": "An internal error occurred. Please try again later.",
                }
            ),
            500,
        )


@metrics_bp.route("/api/metrics/research/<int:research_id>")
def api_research_metrics(research_id):
    """Get metrics for a specific research."""
    try:
        token_counter = TokenCounter()
        metrics = token_counter.get_research_metrics(research_id)
        return jsonify({"status": "success", "metrics": metrics})
    except Exception as e:
        logger.exception(f"Error getting research metrics: {e}")
        return (
            jsonify(
                {
                    "status": "error",
                    "message": "An internal error occurred. Please try again later.",
                }
            ),
            500,
        )


@metrics_bp.route("/api/metrics/research/<int:research_id>/timeline")
def api_research_timeline_metrics(research_id):
    """Get timeline metrics for a specific research."""
    try:
        token_counter = TokenCounter()
        timeline_metrics = token_counter.get_research_timeline_metrics(
            research_id
        )
        return jsonify({"status": "success", "metrics": timeline_metrics})
    except Exception as e:
        logger.exception(f"Error getting research timeline metrics: {e}")
        return (
            jsonify(
                {
                    "status": "error",
                    "message": "An internal error occurred. Please try again later.",
                }
            ),
            500,
        )


@metrics_bp.route("/api/metrics/research/<int:research_id>/search")
def api_research_search_metrics(research_id):
    """Get search metrics for a specific research."""
    try:
        search_tracker = get_search_tracker()
        search_metrics = search_tracker.get_research_search_metrics(research_id)
        return jsonify({"status": "success", "metrics": search_metrics})
    except Exception as e:
        logger.exception(f"Error getting research search metrics: {e}")
        return (
            jsonify(
                {
                    "status": "error",
                    "message": "An internal error occurred. Please try again later.",
                }
            ),
            500,
        )


@metrics_bp.route("/api/metrics/enhanced")
def api_enhanced_metrics():
    """Get enhanced Phase 1 tracking metrics."""
    try:
        # Get time period and research mode from query parameters
        period = request.args.get("period", "30d")
        research_mode = request.args.get("mode", "all")

        token_counter = TokenCounter()
        search_tracker = get_search_tracker()

        enhanced_metrics = token_counter.get_enhanced_metrics(
            period=period, research_mode=research_mode
        )

        # Add search time series data for the chart
        search_time_series = search_tracker.get_search_time_series(
            period=period, research_mode=research_mode
        )
        enhanced_metrics["search_time_series"] = search_time_series

        # Add rating analytics
        rating_analytics = get_rating_analytics(period, research_mode)
        enhanced_metrics.update(rating_analytics)

        return jsonify(
            {
                "status": "success",
                "metrics": enhanced_metrics,
                "period": period,
                "research_mode": research_mode,
            }
        )
    except Exception as e:
        logger.exception(f"Error getting enhanced metrics: {e}")
        return (
            jsonify(
                {
                    "status": "error",
                    "message": "An internal error occurred. Please try again later.",
                }
            ),
            500,
        )


@metrics_bp.route("/api/ratings/<int:research_id>", methods=["GET"])
def api_get_research_rating(research_id):
    """Get rating for a specific research session."""
    try:
        from ...metrics.database import get_metrics_db
        from ...metrics.db_models import ResearchRating

        db = get_metrics_db()
        with db.get_session() as session:
            rating = (
                session.query(ResearchRating)
                .filter_by(research_id=research_id)
                .first()
            )

            if rating:
                return jsonify(
                    {
                        "status": "success",
                        "rating": rating.rating,
                        "rated_at": rating.rated_at.isoformat(),
                        "updated_at": rating.updated_at.isoformat(),
                    }
                )
            else:
                return jsonify({"status": "success", "rating": None})

    except Exception as e:
        logger.exception(f"Error getting research rating: {e}")
        return (
            jsonify(
                {
                    "status": "error",
                    "message": "An internal error occurred. Please try again later.",
                }
            ),
            500,
        )


@metrics_bp.route("/api/ratings/<int:research_id>", methods=["POST"])
def api_save_research_rating(research_id):
    """Save or update rating for a specific research session."""
    try:
        from sqlalchemy import func

        from ...metrics.database import get_metrics_db
        from ...metrics.db_models import ResearchRating

        data = request.get_json()
        rating_value = data.get("rating")

        if (
            not rating_value
            or not isinstance(rating_value, int)
            or rating_value < 1
            or rating_value > 5
        ):
            return (
                jsonify(
                    {
                        "status": "error",
                        "message": "Rating must be an integer between 1 and 5",
                    }
                ),
                400,
            )

        db = get_metrics_db()
        with db.get_session() as session:
            # Check if rating already exists
            existing_rating = (
                session.query(ResearchRating)
                .filter_by(research_id=research_id)
                .first()
            )

            if existing_rating:
                # Update existing rating
                existing_rating.rating = rating_value
                existing_rating.updated_at = func.now()
            else:
                # Create new rating
                new_rating = ResearchRating(
                    research_id=research_id, rating=rating_value
                )
                session.add(new_rating)

            session.commit()

            return jsonify(
                {
                    "status": "success",
                    "message": "Rating saved successfully",
                    "rating": rating_value,
                }
            )

    except Exception as e:
        logger.exception(f"Error saving research rating: {e}")
        return (
            jsonify(
                {
                    "status": "error",
                    "message": "An internal error occurred. Please try again later.",
                }
            ),
            500,
        )


@metrics_bp.route("/star-reviews")
def star_reviews():
    """Display star reviews metrics page."""
    return render_template_with_defaults("pages/star_reviews.html")


@metrics_bp.route("/costs")
def cost_analytics():
    """Display cost analytics page."""
    return render_template_with_defaults("pages/cost_analytics.html")


@metrics_bp.route("/api/star-reviews")
def api_star_reviews():
    """Get star reviews analytics data."""
    try:
        period = request.args.get("period", "30d")

        with get_db_session() as session:
            # Build base query with time filter
            base_query = session.query(ResearchRating)
            time_condition = get_time_filter_condition(
                period, ResearchRating.rated_at
            )
            if time_condition is not None:
                base_query = base_query.filter(time_condition)

            # Overall rating statistics
            overall_stats = session.query(
                func.avg(ResearchRating.rating).label("avg_rating"),
                func.count(ResearchRating.rating).label("total_ratings"),
                func.sum(case((ResearchRating.rating == 5, 1), else_=0)).label(
                    "five_star"
                ),
                func.sum(case((ResearchRating.rating == 4, 1), else_=0)).label(
                    "four_star"
                ),
                func.sum(case((ResearchRating.rating == 3, 1), else_=0)).label(
                    "three_star"
                ),
                func.sum(case((ResearchRating.rating == 2, 1), else_=0)).label(
                    "two_star"
                ),
                func.sum(case((ResearchRating.rating == 1, 1), else_=0)).label(
                    "one_star"
                ),
            )

            if time_condition is not None:
                overall_stats = overall_stats.filter(time_condition)

            overall_stats = overall_stats.first()

            # Ratings by LLM model (get from token_usage since Research doesn't have model field)
            llm_ratings_query = session.query(
                func.coalesce(TokenUsage.model_name, "Unknown").label("model"),
                func.avg(ResearchRating.rating).label("avg_rating"),
                func.count(ResearchRating.rating).label("rating_count"),
                func.sum(case((ResearchRating.rating >= 4, 1), else_=0)).label(
                    "positive_ratings"
                ),
            ).outerjoin(
                TokenUsage, ResearchRating.research_id == TokenUsage.research_id
            )

            if time_condition is not None:
                llm_ratings_query = llm_ratings_query.filter(time_condition)

            llm_ratings = (
                llm_ratings_query.group_by(TokenUsage.model_name)
                .order_by(func.avg(ResearchRating.rating).desc())
                .all()
            )

            # Ratings by search engine (join with token_usage to get search engine info)
            search_engine_ratings_query = session.query(
                func.coalesce(
                    TokenUsage.search_engine_selected, "Unknown"
                ).label("search_engine"),
                func.avg(ResearchRating.rating).label("avg_rating"),
                func.count(ResearchRating.rating).label("rating_count"),
                func.sum(case((ResearchRating.rating >= 4, 1), else_=0)).label(
                    "positive_ratings"
                ),
            ).outerjoin(
                TokenUsage, ResearchRating.research_id == TokenUsage.research_id
            )

            if time_condition is not None:
                search_engine_ratings_query = (
                    search_engine_ratings_query.filter(time_condition)
                )

            search_engine_ratings = (
                search_engine_ratings_query.group_by(
                    TokenUsage.search_engine_selected
                )
                .having(func.count(ResearchRating.rating) > 0)
                .order_by(func.avg(ResearchRating.rating).desc())
                .all()
            )

            # Rating trends over time
            rating_trends_query = session.query(
                func.date(ResearchRating.rated_at).label("date"),
                func.avg(ResearchRating.rating).label("avg_rating"),
                func.count(ResearchRating.rating).label("daily_count"),
            )

            if time_condition is not None:
                rating_trends_query = rating_trends_query.filter(time_condition)

            rating_trends = (
                rating_trends_query.group_by(func.date(ResearchRating.rated_at))
                .order_by("date")
                .all()
            )

            # Recent ratings with research details
            recent_ratings_query = (
                session.query(
                    ResearchRating.rating,
                    ResearchRating.rated_at,
                    ResearchRating.research_id,
                    Research.query,
                    Research.mode,
                    TokenUsage.model_name,
                    Research.created_at,
                )
                .outerjoin(Research, ResearchRating.research_id == Research.id)
                .outerjoin(
                    TokenUsage,
                    ResearchRating.research_id == TokenUsage.research_id,
                )
            )

            if time_condition is not None:
                recent_ratings_query = recent_ratings_query.filter(
                    time_condition
                )

            recent_ratings = (
                recent_ratings_query.order_by(ResearchRating.rated_at.desc())
                .limit(20)
                .all()
            )

            return jsonify(
                {
                    "overall_stats": {
                        "avg_rating": round(overall_stats.avg_rating or 0, 2),
                        "total_ratings": overall_stats.total_ratings or 0,
                        "rating_distribution": {
                            "5": overall_stats.five_star or 0,
                            "4": overall_stats.four_star or 0,
                            "3": overall_stats.three_star or 0,
                            "2": overall_stats.two_star or 0,
                            "1": overall_stats.one_star or 0,
                        },
                    },
                    "llm_ratings": [
                        {
                            "model": rating.model,
                            "avg_rating": round(rating.avg_rating or 0, 2),
                            "rating_count": rating.rating_count or 0,
                            "positive_ratings": rating.positive_ratings or 0,
                            "satisfaction_rate": round(
                                (rating.positive_ratings or 0)
                                / max(rating.rating_count or 1, 1)
                                * 100,
                                1,
                            ),
                        }
                        for rating in llm_ratings
                    ],
                    "search_engine_ratings": [
                        {
                            "search_engine": rating.search_engine,
                            "avg_rating": round(rating.avg_rating or 0, 2),
                            "rating_count": rating.rating_count or 0,
                            "positive_ratings": rating.positive_ratings or 0,
                            "satisfaction_rate": round(
                                (rating.positive_ratings or 0)
                                / max(rating.rating_count or 1, 1)
                                * 100,
                                1,
                            ),
                        }
                        for rating in search_engine_ratings
                    ],
                    "rating_trends": [
                        {
                            "date": str(trend.date),
                            "avg_rating": round(trend.avg_rating or 0, 2),
                            "count": trend.daily_count or 0,
                        }
                        for trend in rating_trends
                    ],
                    "recent_ratings": [
                        {
                            "rating": rating.rating,
                            "rated_at": str(rating.rated_at),
                            "research_id": rating.research_id,
                            "query": (
                                rating.query
                                if rating.query
                                else f"Research Session #{rating.research_id}"
                            ),
                            "mode": rating.mode
                            if rating.mode
                            else "Standard Research",
                            "llm_model": (
                                rating.model_name
                                if rating.model_name
                                else "LLM Model"
                            ),
                            "created_at": (
                                str(rating.created_at)
                                if rating.created_at
                                else str(rating.rated_at)
                            ),
                        }
                        for rating in recent_ratings
                    ],
                }
            )

    except Exception:
        logger.exception("Error getting star reviews data")
        return (
            jsonify(
                {"error": "An internal error occurred. Please try again later."}
            ),
            500,
        )


@metrics_bp.route("/api/pricing")
def api_pricing():
    """Get current LLM pricing data."""
    try:
        from ...metrics.pricing.pricing_fetcher import PricingFetcher

        # Use static pricing data instead of async
        fetcher = PricingFetcher()
        pricing_data = fetcher.static_pricing

        return jsonify(
            {
                "status": "success",
                "pricing": pricing_data,
                "last_updated": datetime.now().isoformat(),
                "note": "Pricing data is from static configuration. Real-time APIs not available for most providers.",
            }
        )

    except Exception:
        logger.exception("Error fetching pricing data")
        return jsonify({"error": "Internal Server Error"}), 500


@metrics_bp.route("/api/pricing/<model_name>")
def api_model_pricing(model_name):
    """Get pricing for a specific model."""
    try:
        # Optional provider parameter
        provider = request.args.get("provider")

        from ...metrics.pricing.cost_calculator import CostCalculator

        # Use synchronous approach with cached/static pricing
        calculator = CostCalculator()
        pricing = calculator.cache.get_model_pricing(
            model_name
        ) or calculator.calculate_cost_sync(model_name, 1000, 1000).get(
            "pricing_used", {}
        )

        return jsonify(
            {
                "status": "success",
                "model": model_name,
                "provider": provider,
                "pricing": pricing,
                "last_updated": datetime.now().isoformat(),
            }
        )

    except Exception as e:
        logger.error(f"Error getting pricing for {model_name}: {e}")
        return jsonify({"error": "An internal error occurred"}), 500


@metrics_bp.route("/api/cost-calculation", methods=["POST"])
def api_cost_calculation():
    """Calculate cost for token usage."""
    try:
        data = request.get_json()

        if not data:
            return jsonify({"error": "No data provided"}), 400

        model_name = data.get("model_name")
        provider = data.get("provider")  # Optional provider parameter
        prompt_tokens = data.get("prompt_tokens", 0)
        completion_tokens = data.get("completion_tokens", 0)

        if not model_name:
            return jsonify({"error": "model_name is required"}), 400

        from ...metrics.pricing.cost_calculator import CostCalculator

        # Use synchronous cost calculation
        calculator = CostCalculator()
        cost_data = calculator.calculate_cost_sync(
            model_name, prompt_tokens, completion_tokens
        )

        return jsonify(
            {
                "status": "success",
                "model_name": model_name,
                "provider": provider,
                "prompt_tokens": prompt_tokens,
                "completion_tokens": completion_tokens,
                "total_tokens": prompt_tokens + completion_tokens,
                **cost_data,
            }
        )

    except Exception as e:
        logger.error(f"Error calculating cost: {e}")
        return jsonify({"error": "An internal error occurred"}), 500


@metrics_bp.route("/api/research-costs/<int:research_id>")
def api_research_costs(research_id):
    """Get cost analysis for a specific research session."""
    try:
        with get_db_session() as session:
            # Get token usage records for this research
            usage_records = (
                session.query(TokenUsage)
                .filter(TokenUsage.research_id == research_id)
                .all()
            )

            if not usage_records:
                return jsonify(
                    {
                        "status": "success",
                        "research_id": research_id,
                        "total_cost": 0.0,
                        "message": "No token usage data found for this research session",
                    }
                )

            # Convert to dict format for cost calculation
            usage_data = []
            for record in usage_records:
                usage_data.append(
                    {
                        "model_name": record.model_name,
                        "provider": getattr(
                            record, "provider", None
                        ),  # Handle both old and new records
                        "prompt_tokens": record.prompt_tokens,
                        "completion_tokens": record.completion_tokens,
                        "timestamp": record.timestamp,
                    }
                )

            from ...metrics.pricing.cost_calculator import CostCalculator

            # Use synchronous calculation for research costs
            calculator = CostCalculator()
            costs = []
            for record in usage_data:
                cost_data = calculator.calculate_cost_sync(
                    record["model_name"],
                    record["prompt_tokens"],
                    record["completion_tokens"],
                )
                costs.append({**record, **cost_data})

            total_cost = sum(c["total_cost"] for c in costs)
            total_prompt_tokens = sum(r["prompt_tokens"] for r in usage_data)
            total_completion_tokens = sum(
                r["completion_tokens"] for r in usage_data
            )

            cost_summary = {
                "total_cost": round(total_cost, 6),
                "total_tokens": total_prompt_tokens + total_completion_tokens,
                "prompt_tokens": total_prompt_tokens,
                "completion_tokens": total_completion_tokens,
            }

            return jsonify(
                {
                    "status": "success",
                    "research_id": research_id,
                    **cost_summary,
                }
            )

    except Exception as e:
        logger.error(f"Error getting research costs for {research_id}: {e}")
        return jsonify({"error": "An internal error occurred"}), 500


@metrics_bp.route("/api/cost-analytics")
def api_cost_analytics():
    """Get cost analytics across all research sessions."""
    try:
        period = request.args.get("period", "30d")

        # Add error handling for empty data
        with get_db_session() as session:
            # Get token usage for the period
            query = session.query(TokenUsage)
            time_condition = get_time_filter_condition(
                period, TokenUsage.timestamp
            )
            if time_condition is not None:
                query = query.filter(time_condition)

            usage_records = query.all()

            if not usage_records:
                return jsonify(
                    {
                        "status": "success",
                        "period": period,
                        "total_cost": 0.0,
                        "message": "No token usage data found for this period",
                    }
                )

            # Convert to dict format
            usage_data = []
            for record in usage_records:
                usage_data.append(
                    {
                        "model_name": record.model_name,
                        "provider": getattr(
                            record, "provider", None
                        ),  # Handle both old and new records
                        "prompt_tokens": record.prompt_tokens,
                        "completion_tokens": record.completion_tokens,
                        "research_id": record.research_id,
                        "timestamp": record.timestamp,
                    }
                )

            from ...metrics.pricing.cost_calculator import CostCalculator

            # Use synchronous calculation
            calculator = CostCalculator()

            # Calculate overall costs
            costs = []
            for record in usage_data:
                cost_data = calculator.calculate_cost_sync(
                    record["model_name"],
                    record["prompt_tokens"],
                    record["completion_tokens"],
                )
                costs.append({**record, **cost_data})

            total_cost = sum(c["total_cost"] for c in costs)
            total_prompt_tokens = sum(r["prompt_tokens"] for r in usage_data)
            total_completion_tokens = sum(
                r["completion_tokens"] for r in usage_data
            )

            cost_summary = {
                "total_cost": round(total_cost, 6),
                "total_tokens": total_prompt_tokens + total_completion_tokens,
                "prompt_tokens": total_prompt_tokens,
                "completion_tokens": total_completion_tokens,
            }

            # Group by research_id for per-research costs
            research_costs = {}
            for record in usage_data:
                rid = record["research_id"]
                if rid not in research_costs:
                    research_costs[rid] = []
                research_costs[rid].append(record)

            # Calculate cost per research
            research_summaries = {}
            for rid, records in research_costs.items():
                research_total = 0
                for record in records:
                    cost_data = calculator.calculate_cost_sync(
                        record["model_name"],
                        record["prompt_tokens"],
                        record["completion_tokens"],
                    )
                    research_total += cost_data["total_cost"]
                research_summaries[rid] = {
                    "total_cost": round(research_total, 6)
                }

            # Top expensive research sessions
            top_expensive = sorted(
                [
                    (rid, data["total_cost"])
                    for rid, data in research_summaries.items()
                ],
                key=lambda x: x[1],
                reverse=True,
            )[:10]

            return jsonify(
                {
                    "status": "success",
                    "period": period,
                    "overview": cost_summary,
                    "top_expensive_research": [
                        {"research_id": rid, "total_cost": cost}
                        for rid, cost in top_expensive
                    ],
                    "research_count": len(research_summaries),
                }
            )

    except Exception as e:
        logger.exception(f"Error getting cost analytics: {e}")
        # Return a more graceful error response
        return (
            jsonify(
                {
                    "status": "success",
                    "period": period,
                    "overview": {
                        "total_cost": 0.0,
                        "total_tokens": 0,
                        "prompt_tokens": 0,
                        "completion_tokens": 0,
                    },
                    "top_expensive_research": [],
                    "research_count": 0,
                    "error": "Cost analytics temporarily unavailable",
                }
            ),
            200,
        )  # Return 200 to avoid breaking the UI
