"""
Backtesting Service.

This module provides the service layer for backtesting operations,
integrating with the database to run backtesting on historical matches.
"""

import logging
from datetime import datetime
from typing import Dict, List, Any, Optional

from sqlalchemy.orm import Session

from app.models.match import Match
from app.models.energy_score import EnergyScore
from app.ml.backtesting import (
    run_backtesting_batch,
    export_to_json,
    export_to_csv,
    export_to_html,
    filter_matches_by_league,
    filter_matches_by_period
)

logger = logging.getLogger(__name__)


class BacktestingService:
    """Service for running backtesting on historical match data."""

    def __init__(self, db: Session):
        """
        Initialize backtesting service.

        Args:
            db: SQLAlchemy database session
        """
        self.db = db

    def get_historical_matches(
        self,
        leagues: Optional[List[str]] = None,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None
    ) -> List[Dict[str, Any]]:
        """
        Retrieve historical matches with energy scores and actual results.

        Args:
            leagues: Optional list of leagues to filter by
            start_date: Optional start date for filtering
            end_date: Optional end date for filtering

        Returns:
            List of match dictionaries with energy scores and actual winners

        Raises:
            ValueError: If no historical matches found
        """
        logger.info("Fetching historical matches from database")

        # Query matches that have actual_winner set (completed matches)
        query = self.db.query(Match).filter(
            Match.actual_winner.isnot(None)
        )

        # Apply filters
        if leagues:
            query = query.filter(Match.league.in_(leagues))

        if start_date:
            query = query.filter(Match.date >= start_date)

        if end_date:
            query = query.filter(Match.date <= end_date)

        matches = query.all()

        if not matches:
            raise ValueError(
                "No historical matches found. Please populate database with "
                "historical match data and actual winners before running backtesting."
            )

        logger.info(f"Found {len(matches)} historical matches")

        # Convert to list of dictionaries with energy scores
        match_data = []
        for match in matches:
            # Get energy scores for this match
            home_energy_score = self.db.query(EnergyScore).filter(
                EnergyScore.match_id == match.id
            ).first()

            if not home_energy_score:
                logger.warning(f"No energy score found for match {match.id}, skipping")
                continue

            match_dict = {
                'match_id': match.id,
                'home_team': match.home_team,
                'away_team': match.away_team,
                'date': match.date,
                'league': match.league,
                'home_energy': home_energy_score.home_energy,
                'away_energy': home_energy_score.away_energy,
                'actual_winner': match.actual_winner
            }

            match_data.append(match_dict)

        logger.info(f"Processed {len(match_data)} matches with energy scores")

        return match_data

    def run_backtesting(
        self,
        leagues: Optional[List[str]] = None,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None
    ) -> Dict[str, Any]:
        """
        Run backtesting on historical matches with optional filters.

        Args:
            leagues: Optional list of leagues to filter by
            start_date: Optional start date for filtering
            end_date: Optional end date for filtering

        Returns:
            Dictionary containing backtesting results

        Raises:
            ValueError: If no matches found or matches lack required data
        """
        logger.info("Starting backtesting process")

        # Get historical matches
        matches = self.get_historical_matches(
            leagues=leagues,
            start_date=start_date,
            end_date=end_date
        )

        # Apply filters
        if leagues:
            matches = filter_matches_by_league(matches, leagues)

        if start_date or end_date:
            matches = filter_matches_by_period(matches, start_date, end_date)

        if not matches:
            raise ValueError("No matches match the specified filters")

        logger.info(f"Running backtesting on {len(matches)} matches")

        # Run backtesting
        result = run_backtesting_batch(matches)

        # Log results
        logger.info(
            f"Backtesting complete: {result['total_matches']} matches, "
            f"{result['correct_predictions']} correct, "
            f"{result['accuracy']:.2f}% accuracy, "
            f"status: {result['status']}"
        )

        return result

    def export_results(
        self,
        backtesting_result: Dict[str, Any],
        format: str = 'json'
    ) -> str:
        """
        Export backtesting results in specified format.

        Args:
            backtesting_result: Result from run_backtesting
            format: Export format ('json', 'csv', or 'html')

        Returns:
            Formatted string in specified format

        Raises:
            ValueError: If format is not supported
        """
        logger.info(f"Exporting backtesting results as {format}")

        if format == 'json':
            return export_to_json(backtesting_result)
        elif format == 'csv':
            return export_to_csv(backtesting_result)
        elif format == 'html':
            return export_to_html(backtesting_result)
        else:
            raise ValueError(
                f"Unsupported export format: {format}. "
                "Supported formats are: json, csv, html"
            )
