# src/eojhl_managers.py
import logging
from typing import Any, Dict, Optional, List
import os
import json
import time
import re
import requests
from datetime import datetime, timezone, date
from pathlib import Path

from src.base_classes.hockey import Hockey, HockeyLive
from src.base_classes.sports import SportsRecent, SportsUpcoming
from src.cache_manager import CacheManager
from src.display_manager import DisplayManager

# Import the API counter function from web interface
try:
    from web_interface_v2 import increment_api_counter
except ImportError:
    # Fallback if web interface is not available
    def increment_api_counter(kind: str, count: int = 1):
        pass

LOCAL_EOJHL_FILE = "data/eojhl_scoreboard.json"
LOCAL_EOJHL_STANDINGS = "data/eojhl_standings.json"

class BaseEOJHLManager(Hockey):
    """Base class for EOJHL managers; renders scoreboard and supplies leaderboard data."""
    def __init__(self, config: Dict[str, Any], display_manager: DisplayManager, cache_manager: CacheManager):
        self.logger = logging.getLogger('EOJHL')
        super().__init__(config=config, display_manager=display_manager, cache_manager=cache_manager,
                         logger=self.logger, sport_key="eojhl")
        self.league = "eojhl"
        # EOJHL specifics used for leaderboard data
        self.conferences: List[str] = ["martin", "richardson"]
        self.league_logo_path: str = "assets/sports/eojhl_logos/EOJHL.png"
        self._last_standings_read: float = 0.0
        self._cached_standings: Optional[Dict[str, List[Dict[str, Any]]]] = None

    # ---------- Leaderboard data providers ----------
    def standings_provider(self) -> Dict[str, List[Dict[str, Any]]]:
        """
        Read local standings JSON and return {"richardson":[...], "martin":[...]}.
        The LeaderboardManager will call this at most once per hour (via its update_interval).
        """
        try:
            with open(LOCAL_EOJHL_STANDINGS, "r") as f:
                data = json.load(f)
            return {
                "martin": data.get("martin", []),
                "richardson": data.get("richardson", []),
            }
        except Exception as e:
            self.logger.error(f"Failed to load EOJHL standings JSON: {e}")
            return {"martin": [], "richardson": []}

    def get_league_data(self) -> Dict[str, Any]:
        """
        Return all static and dynamic data the generic LeaderboardManager needs.
        """
        return {
            "conferences": self.conferences,
            "league_logo": self.league_logo_path,
            "standings_provider": self.standings_provider,
        }

    # ---------- Scoreboard methods ----------
    def _fetch_todays_games(self) -> Optional[Dict]:
        """Fetch today's games for live updates using JSONP API."""
        today = date.today().strftime("%Y-%m-%d")
        url = (
            "https://lscluster.hockeytech.com/feed/index.php"
            f"?feed=statviewfeed&view=schedule_day&date={today}"
            "&site_id=2&key=1defb601c9b37c24&client_code=eojhl"
            "&league_id=2&season_id=110&conference_id=undefined"
            "&division_id=-1&team=-1&lang=en&forceDate=true"
            "&useSeason=false&allLeagues=0&callback=angular.callbacks._2"
        )
        
        try:
            self.logger.info(f"Fetching EOJHL live games for {today}")
            increment_api_counter("eojhl")
            
            response = self.session.get(url, headers=self.headers, timeout=10)
            response.raise_for_status()
            raw = response.text
            
            # Strip JSONP wrapper (angular.callbacks._2(...))
            if "angular.callbacks" in raw:
                match = re.search(r'angular\.callbacks\._\d+\((.+)\)\s*$', raw, re.DOTALL)
                if match:
                    raw = match.group(1)
                else:
                    # Fallback: find first '(' and last ')'
                    raw = raw[raw.find("(")+1 : raw.rfind(")")]
            
            data = json.loads(raw)
            
            # Log the top-level structure for debugging
            if isinstance(data, dict):
                self.logger.info(f"EOJHL API response keys: {list(data.keys())}")
            elif isinstance(data, list):
                self.logger.info(f"EOJHL API response is a list with {len(data)} games")
            
            # Convert to ESPN-like format for compatibility with base classes
            games = []
            if isinstance(data, list):
                # Direct list of games
                games = data
            elif isinstance(data, dict):
                # Try common HockeyTech API structures
                if "SiteKit" in data:
                    site_kit = data["SiteKit"]
                    if isinstance(site_kit, dict):
                        games = site_kit.get("Gamesbydate", [])
                    elif isinstance(site_kit, list):
                        games = site_kit
                elif "Gamesbydate" in data:
                    games = data["Gamesbydate"]
                elif "games" in data:
                    games = data["games"]
            
            if not games:
                self.logger.info(f"No EOJHL games found for {today}")
                return {"events": []}
            
            events = []
            for game in games:
                event = self._convert_eojhl_to_espn_format(game)
                if event:
                    events.append(event)
            
            self.logger.info(f"Successfully fetched {len(events)} EOJHL games")
            return {"events": events}
            
        except requests.exceptions.RequestException as e:
            self.logger.error(f"API error fetching EOJHL games: {e}")
            return None
        except json.JSONDecodeError as e:
            self.logger.error(f"JSON decode error for EOJHL data: {e}")
            return None
        except Exception as e:
            self.logger.error(f"Unexpected error fetching EOJHL games: {e}", exc_info=True)
            return None

    def _convert_eojhl_to_espn_format(self, eojhl_game: Dict) -> Optional[Dict]:
        """Convert EOJHL HockeyTech API format to ESPN-like format for base class compatibility."""
        try:
            # Debug: Log first game structure
            if not hasattr(self, '_logged_game_structure'):
                self.logger.info(f"Sample game keys: {list(eojhl_game.keys())}")
                home_team_data_temp = eojhl_game.get("homeTeam", {})
                if isinstance(home_team_data_temp, dict):
                    self.logger.info(f"homeTeam keys: {list(home_team_data_temp.keys())}")
                visiting_team_data_temp = eojhl_game.get("visitingTeam", {})
                if isinstance(visiting_team_data_temp, dict):
                    self.logger.info(f"visitingTeam keys: {list(visiting_team_data_temp.keys())}")
                self._logged_game_structure = True
            
            # Parse HockeyTech format
            game_id = str(eojhl_game.get("id", ""))
            date_played = eojhl_game.get("date", "")
            
            # Extract team data
            home_team_data = eojhl_game.get("homeTeam", {})
            visiting_team_data = eojhl_game.get("visitingTeam", {})
            
            # Team info is nested in 'info'
            home_info = home_team_data.get("info", {})
            visiting_info = visiting_team_data.get("info", {})
            
            # Team abbreviations
            home_abbr = home_info.get("abbr", home_info.get("abbreviation", ""))
            visiting_abbr = visiting_info.get("abbr", visiting_info.get("abbreviation", ""))
            
            # Get shots and goals from stats
            home_stats = home_team_data.get("stats", {})
            visiting_stats = visiting_team_data.get("stats", {})
            
            # Parse shots as integers (they come as strings in the API)
            try:
                home_shots = int(home_stats.get("shots", "0"))
            except (ValueError, TypeError):
                home_shots = 0
            
            try:
                visiting_shots = int(visiting_stats.get("shots", "0"))
            except (ValueError, TypeError):
                visiting_shots = 0
            
            # Parse goals as integers
            try:
                home_goals = int(home_stats.get("goals", "0"))
            except (ValueError, TypeError):
                home_goals = 0
            
            try:
                visiting_goals = int(visiting_stats.get("goals", "0"))
            except (ValueError, TypeError):
                visiting_goals = 0
            
            # Records: wins-losses-(OTLosses+SOLosses) from seasonStats.teamRecord
            home_season_stats = home_team_data.get("seasonStats", {})
            home_record_data = home_season_stats.get("teamRecord", {})
            home_wins = home_record_data.get("wins", 0)
            home_losses = home_record_data.get("losses", 0)
            home_ot = home_record_data.get("OTLosses", 0) + home_record_data.get("SOLosses", 0)
            home_record = f"{home_wins}-{home_losses}-{home_ot}"
            
            visiting_season_stats = visiting_team_data.get("seasonStats", {})
            visiting_record_data = visiting_season_stats.get("teamRecord", {})
            visiting_wins = visiting_record_data.get("wins", 0)
            visiting_losses = visiting_record_data.get("losses", 0)
            visiting_ot = visiting_record_data.get("OTLosses", 0) + visiting_record_data.get("SOLosses", 0)
            visiting_record = f"{visiting_wins}-{visiting_losses}-{visiting_ot}"
            
            # Parse game status for clock and period
            status_str = eojhl_game.get("status", "")
            game_clock = ""
            period_text = ""
            
            if status_str:
                # Split at space: "02:41 3rd" -> ["02:41", "3rd"]
                parts = status_str.split(" ", 1)
                if len(parts) == 2:
                    game_clock = parts[0]  # "02:41"
                    period_text = parts[1]  # "3rd"
                elif len(parts) == 1:
                    # Status might be "Final", "Final/OT", etc.
                    period_text = parts[0]
                    game_clock = ""
            
            # Extract period number for internal use
            periods_data = eojhl_game.get("periods", [])
            period_num = 0
            
            if isinstance(periods_data, list) and len(periods_data) > 0:
                # Get the last period (current period)
                last_period = periods_data[-1]
                if isinstance(last_period, dict):
                    period_info = last_period.get("info", {})
                    period_short_name = period_info.get("shortName", "0")
                    try:
                        period_num = int(period_short_name)
                    except (ValueError, TypeError):
                        period_num = 0
            
            # Determine game state using started and final flags
            started = str(eojhl_game.get("started", "0"))
            final = str(eojhl_game.get("final", "0"))
            
            is_final = final == "1"
            is_live = started == "1" and final == "0"
            is_upcoming = started == "0" and final == "0"
            
            # Build ESPN-like event structure
            event = {
                "id": game_id,
                "date": date_played,
                "competitions": [{
                    "id": game_id,
                    "status": {
                        "type": {
                            "name": "STATUS_IN_PROGRESS" if is_live else ("STATUS_FINAL" if is_final else "STATUS_SCHEDULED"),
                            "state": "in" if is_live else ("post" if is_final else "pre"),
                            "shortDetail": status_str if is_live else ("Final" if is_final else date_played)
                        },
                        "period": period_num,
                        "displayClock": game_clock if is_live else "",
                        "customPeriodText": period_text
                    },
                    "competitors": [
                        {
                            "id": str(home_info.get("id", "")),
                            "homeAway": "home",
                            "team": {
                                "id": str(home_info.get("id", "")),
                                "abbreviation": home_abbr,
                                "name": home_info.get("name", home_abbr),
                                "logo": ""
                            },
                            "score": str(home_goals),
                            "records": [{"summary": home_record}],
                            "statistics": [
                                {"name": "shots", "displayValue": str(home_shots)},
                                {"name": "saves", "displayValue": "0"},
                                {"name": "savePct", "displayValue": "0.0"}
                            ]
                        },
                        {
                            "id": str(visiting_info.get("id", "")),
                            "homeAway": "away",
                            "team": {
                                "id": str(visiting_info.get("id", "")),
                                "abbreviation": visiting_abbr,
                                "name": visiting_info.get("name", visiting_abbr),
                                "logo": ""
                            },
                            "score": str(visiting_goals),
                            "records": [{"summary": visiting_record}],
                            "statistics": [
                                {"name": "shots", "displayValue": str(visiting_shots)},
                                {"name": "saves", "displayValue": "0"},
                                {"name": "savePct", "displayValue": "0.0"}
                            ]
                        }
                    ],
                    "situation": {
                        "isPowerPlay": False,
                        "penalties": ""
                    }
                }]
            }
            
            return event
        except Exception as e:
            self.logger.error(f"Error converting EOJHL game format: {e}", exc_info=True)
            return None

    def _fetch_local_data(self):
        try:
            with open(LOCAL_EOJHL_FILE, "r") as f:
                return json.load(f)
        except Exception as e:
            self.logger.error(f"Failed to load local EOJHL scoreboard JSON: {e}")
            return None

    def _fetch_data(self, date_str: str = None) -> Optional[Dict]:
        """Fetch data - live managers use API, others use local files."""
        if isinstance(self, EOJHLLiveManager):
            # Live games should fetch from API
            return self._fetch_todays_games()
        else:
            # Recent and Upcoming managers use local data
            return self._fetch_local_data()

    def _load_standings_records(self):
        """Load standings file and return dict {abbreviation: record}."""
        try:
            with open(LOCAL_EOJHL_STANDINGS, "r") as f:
                standings = json.load(f)
            lookup = {}
            for div in ("martin", "richardson"):
                for team in standings.get(div, []):
                    abbr = team.get("abbreviation")
                    rec = team.get("record")
                    if abbr and rec:
                        lookup[abbr] = rec
            return lookup
        except Exception as e:
            self.logger.warning(f"Could not load standings records: {e}")
            return {}

    def _extract_game_details(self, game_event: Dict) -> Optional[Dict]:
        """Extract game details with hockey-specific fields for EOJHL."""
        # First get common details
        details, home_team, away_team, status, situation = (
            self._extract_game_details_common(game_event)
        )
        if not details:
            return None
        
        try:
            if not hasattr(self, "_standings_lookup"):
                self._standings_lookup = self._load_standings_records()

            home_abbr = home_team["team"]["abbreviation"]
            away_abbr = away_team["team"]["abbreviation"]
            
            # Get shots data
            home_shots = 0
            away_shots = 0
            try:
                home_shots = next(
                    (int(c["displayValue"]) for c in home_team["statistics"] if c.get("name") == "shots"),
                    0
                )
                away_shots = next(
                    (int(c["displayValue"]) for c in away_team["statistics"] if c.get("name") == "shots"),
                    0
                )
            except (ValueError, KeyError, StopIteration):
                pass
            
            # Get period and clock info
            period = status.get("period", 0)
            display_clock = status.get("displayClock", "0:00")
            
            # Check for custom period text (used by EOJHL)
            period_text = status.get("customPeriodText", "")
            
            if not period_text:
                # Default period text formatting
                if status["type"]["state"] == "in":
                    if period == 0:
                        period_text = "Start"
                    elif period >= 1 and period <= 3:
                        period_text = f"P{period}"
                    elif period > 3:
                        period_text = f"OT{period - 3}"
                elif status["type"]["state"] == "post":
                    if period > 3:
                        period_text = "FINAL/OT"
                    elif period > 4:
                        period_text = "FINAL/SO"
                    else:
                        period_text = "FINAL"
                elif status["type"]["state"] == "pre":
                    period_text = details.get("game_time", "")

            details.update({
                "home_score": home_team.get("score", "0"),
                "away_score": away_team.get("score", "0"),
                "home_logo_path": self.logo_dir / f"{home_abbr}.png",
                "away_logo_path": self.logo_dir / f"{away_abbr}.png",
                "status_text": status["type"]["shortDetail"],
                "home_record": self._standings_lookup.get(home_abbr, "0-0-0"),
                "away_record": self._standings_lookup.get(away_abbr, "0-0-0"),
                "period": period,
                "period_text": period_text,
                "clock": display_clock,
                "power_play": False,
                "penalties": "",
                "home_shots": home_shots,
                "away_shots": away_shots,
            })
            return details
        except Exception as e:
            self.logger.error(f"EOJHL extract error: {e}", exc_info=True)
            return None


class EOJHLLiveManager(BaseEOJHLManager, HockeyLive):
    """Manager for live EOJHL games."""
    def __init__(self, config: Dict[str, Any], display_manager: DisplayManager, cache_manager: CacheManager):
        super().__init__(config, display_manager, cache_manager)
        self.logger = logging.getLogger('EOJHLLiveManager')
        
        # Initialize with test game only if test mode is enabled
        if self.test_mode:
            # Load test data from example_live.jsonp
            try:
                test_file = Path("data/example_live.jsonp")
                with open(test_file, "r") as f:
                    raw = f.read()
                
                # Strip JSONP wrapper
                if "angular.callbacks" in raw:
                    match = re.search(r'angular\.callbacks\._\d+\((.+)\)\s*$', raw, re.DOTALL)
                    if match:
                        raw = match.group(1)
                    else:
                        raw = raw[raw.find("(")+1 : raw.rfind(")")]
                
                test_games = json.loads(raw)
                
                # Convert first game to ESPN format and extract details
                if test_games and len(test_games) > 0:
                    first_game = test_games[0]
                    event = self._convert_eojhl_to_espn_format(first_game)
                    if event:
                        self.current_game = self._extract_game_details(event)
                        if self.current_game:
                            self.live_games = [self.current_game]
                            home_abbr = self.current_game.get('home_abbr', 'UNK')
                            away_abbr = self.current_game.get('away_abbr', 'UNK')
                            self.logger.info(f"Initialized EOJHLLiveManager with test game from example_live.jsonp: {away_abbr} @ {home_abbr}")
                        else:
                            self.logger.error("Failed to extract game details from test data")
                            self.current_game = None
                            self.live_games = []
                    else:
                        self.logger.error("Failed to convert test game to ESPN format")
                        self.current_game = None
                        self.live_games = []
                else:
                    self.logger.error("No games found in example_live.jsonp")
                    self.current_game = None
                    self.live_games = []
                    
            except FileNotFoundError:
                self.logger.error("Test file data/example_live.jsonp not found")
                self.current_game = None
                self.live_games = []
            except Exception as e:
                self.logger.error(f"Error loading test data: {e}", exc_info=True)
                self.current_game = None
                self.live_games = []
        else:
            self.logger.info("Initialized EOJHLLiveManager in live mode")


class EOJHLRecentManager(BaseEOJHLManager, SportsRecent):
    def __init__(self, config, display_manager, cache_manager):
        super().__init__(config, display_manager, cache_manager)
        self.logger = logging.getLogger('EOJHLRecentManager')
        
        # Load recent game title settings
        self.status_titles = self.mode_config.get("status_titles", {
            "RECENT_GAME": "LAST GAME"
        })
        self.title_colors = self.mode_config.get("title_colors", {
            "RECENT_GAME": [0, 51, 204]
        })


class EOJHLUpcomingManager(BaseEOJHLManager, SportsUpcoming):
    def __init__(self, config, display_manager, cache_manager):
        super().__init__(config, display_manager, cache_manager)
        self.logger = logging.getLogger('EOJHLUpcomingManager')
        
        # Load home/away settings
        self.show_home_away = self.mode_config.get("show_home_away", False)
        self.status_titles = self.mode_config.get("status_titles", {
            "GAME_DAY": "GAME DAY",
            "HOME_GAME": "NEXT HOME GAME",
            "AWAY_GAME": "NEXT AWAY GAME"
        })
        self.title_colors = self.mode_config.get("title_colors", {
            "GAME_DAY": [255, 255, 0],
            "HOME_GAME": [0, 200, 255],
            "AWAY_GAME": [0, 255, 128]
        })

    def _fetch_data(self, date_str: str = None):
        data = super()._fetch_data(date_str)
        if not data:
            return None

        now = datetime.now(timezone.utc)
        future_events = []
        for e in data.get("events", []):
            try:
                dt = datetime.strptime(e["date"], "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
                if dt >= now:
                    future_events.append((dt, e))
            except Exception as ex:
                self.logger.warning(f"Skipping event with bad date: {ex}")

        future_events.sort(key=lambda x: x[0])
        data["events"] = [e for _, e in future_events]
        return data
    
    def _get_game_status_type(self, game: Dict, favorite_team: str) -> str:
        """Determine if game is GAME_DAY, HOME_GAME, or AWAY_GAME."""
        try:
            game_date = game.get('start_time_utc')
            if not game_date:
                return "AWAY_GAME"
            
            now = datetime.now(timezone.utc)
            today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
            today_end = now.replace(hour=23, minute=59, second=59, microsecond=999999)
            
            # Check if game is today
            if today_start <= game_date <= today_end:
                return "GAME_DAY"
            
            # Check if it's a home or away game
            if game.get('home_abbr') == favorite_team:
                return "HOME_GAME"
            else:
                return "AWAY_GAME"
                
        except Exception as e:
            self.logger.error(f"Error determining game status type: {e}")
            return "AWAY_GAME"