import time
import logging
import sys

from pytz import timezone
from datetime import datetime, time as time_obj

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s.%(msecs)03d - %(levelname)s:%(name)s:%(message)s',
    datefmt='%H:%M:%S',
    stream=sys.stdout
)

from src.clock import Clock
from src.display_manager import DisplayManager
from src.config_manager import ConfigManager
from src.cache_manager import CacheManager
from src.eojhl_managers import EOJHLLiveManager, EOJHLRecentManager, EOJHLUpcomingManager
from src.leaderboard_manager import LeaderboardManager
from src.sponsor_manager import EOJHLSponsorsManager

logger = logging.getLogger(__name__)

class DisplayController:
    def __init__(self):
        start_time = time.time()
        logger.info("Starting DisplayController initialization")

        # Load config
        self.config_manager = ConfigManager()
        self.config = self.config_manager.load_config()
        self.cache_manager = CacheManager()
        logger.info("Config loaded in %.3f seconds", time.time() - start_time)

        # Initialize display manager
        self.display_manager = DisplayManager(self.config)
        logger.info("DisplayManager initialized")

        # Initialize clock if enabled
        init_time = time.time()
        self.clock = Clock(self.display_manager, self.config) if self.config.get('clock', {}).get('enabled', True) else None
        logger.info("Display modes initialized in %.3f seconds", time.time() - init_time)

        self.is_display_active = True
        self._load_schedule_config()

        # --- League Managers Dictionary ---
        self.league_managers = {}

        # EOJHL Managers
        if self.config.get('eojhl_scoreboard', {}).get('enabled', False):
            eojhl_recent = EOJHLRecentManager(self.config, self.display_manager, self.cache_manager)
            eojhl_upcoming = EOJHLUpcomingManager(self.config, self.display_manager, self.cache_manager)
            eojhl_live = EOJHLLiveManager(self.config, self.display_manager, self.cache_manager)

            self.league_managers["eojhl"] = {
                "recent": eojhl_recent,
                "upcoming": eojhl_upcoming,
                "live": eojhl_live,
                "leaderboard": LeaderboardManager(self.config, self.display_manager, eojhl_recent.get_league_data())
            }

        # TODO: Add CCHL managers in the same pattern when ready

        # Sponsors
        self.sponsors = EOJHLSponsorsManager(self.config, self.display_manager) if self.config.get('sponsors', {}).get('enabled', False) else None

        # Build available modes list from league_order
        self.available_modes = []
        if self.clock: self.available_modes.append("clock")

        for league in sorted(self.config.get("league_order", {}), key=lambda k: self.config["league_order"][k]):
            managers = self.league_managers.get(league, {})
            # Only add leaderboard if enabled in config
            if managers.get("leaderboard") and self.config["leaderboard"]["enabled_sports"].get(league, {}).get("enabled", False):
                self.available_modes.append(f"{league}_leaderboard")
            if managers.get("recent"):
                self.available_modes.append(f"{league}_recent")
            if managers.get("upcoming"):
                self.available_modes.append(f"{league}_upcoming")
            # live is handled separately if you want to prioritize it

        if self.sponsors:
            self.available_modes.append("sponsors")

        if self.config.get("team_info", {}).get("enabled", False):
            self.available_modes.append("team_info")

        self.current_mode_index = 0
        self.last_switch = time.time()
        self.force_clear = True
        self.update_interval = 0.01

        logger.info(f"DisplayController initialized with modes: {self.available_modes}")

        # --- SCHEDULING ---
        self.is_display_active = True
        self._load_schedule_config() # Load schedule config once at startup
    
    def run_transition(self, when="before"):
        """Run transition effect either before or after a mode."""
        tcfg = self.config.get("transitions", {})
        ttype = tcfg.get("type", "fade")

        if ttype == "fade":
            dur = tcfg.get("fade_duration", 0.4)
            steps = tcfg.get("fade_steps", 6)
            easing = tcfg.get("easing", True)
            if when == "before":
                self.display_manager.fade_in(duration=dur, steps=steps, easing=easing)
            else:
                self.display_manager.fade_out(duration=dur, steps=steps, easing=easing)

        elif ttype == "cut":
            dur = tcfg.get("cut_duration", 0.2)
            if when == "before":
                # nothing to fade in, just show the mode
                return
            else:
                self.display_manager.cut_to_black(duration=dur)

    def _load_schedule_config(self):
        """Load schedule configuration once at startup."""
        schedule_config = self.config.get('schedule', {})
        self.schedule_enabled = schedule_config.get('enabled', False)
        try:
            self.start_time = datetime.strptime(schedule_config.get('start_time', '07:00'), '%H:%M').time()
            self.end_time = datetime.strptime(schedule_config.get('end_time', '22:00'), '%H:%M').time()
            logger.info(f"Schedule loaded: enabled={self.schedule_enabled}, start={self.start_time}, end={self.end_time}")
        except (ValueError, TypeError):
            logger.warning("Invalid time format in schedule config. Using defaults.")
            self.start_time = time_obj(7, 0)
            self.end_time = time_obj(22, 0)

    def _check_schedule(self):
        """Check if the display should be active based on the schedule."""
        if not self.schedule_enabled:
            if not self.is_display_active:
                logger.info("Schedule is disabled. Activating display.")
                self.is_display_active = True
            return

        local_tz = timezone(self.config.get("timezone", "America/Toronto"))
        now_time = datetime.now(local_tz).time()

        if self.start_time <= self.end_time:
            should_be_active = self.start_time <= now_time < self.end_time
        else:
            should_be_active = now_time >= self.start_time or now_time < self.end_time

        if should_be_active and not self.is_display_active:
            logger.info("Within scheduled time. Activating display.")
            self.is_display_active = True
            self.force_clear = True
        elif not should_be_active and self.is_display_active:
            logger.info("Outside of scheduled time. Deactivating display.")
            self.display_manager.clear()
            self.is_display_active = False
    

def main():
    controller = DisplayController()
    logger.info("Entering main display loop")

    try:
        while True:
            controller._check_schedule()

            if not controller.is_display_active:
                controller.display_manager.clear()
                time.sleep(5)
                continue

            if not controller.available_modes:
                logger.warning("No display modes available")
                time.sleep(5)
                continue
            
            # Check for live games with priority for each league
            live_game_shown = False
            for league in controller.league_managers:
                league_config = controller.config.get(f"{league}_scoreboard", {})
                if league_config.get("live_priority", False):
                    live_mgr = controller.league_managers[league].get("live")
                    if live_mgr:
                        # Update live manager to check for live games
                        live_mgr.update()
                        if live_mgr.live_games:
                            logger.info(f"Live {league.upper()} games detected with priority - displaying live games")
                            live_update_interval = league_config.get("live_update_interval", 30)
                            
                            # Display live games continuously until they end
                            while live_mgr.live_games:
                                controller._check_schedule()
                                if not controller.is_display_active:
                                    break
                                
                                live_mgr.display()
                                time.sleep(1)  # Small sleep for display refresh
                                
                                # Check if it's time to update live data
                                current_time = time.time()
                                if current_time - live_mgr.last_update >= live_update_interval:
                                    live_mgr.update()
                                    if not live_mgr.live_games:
                                        logger.info(f"No more live {league.upper()} games - returning to normal rotation")
                                        break
                            
                            live_game_shown = True
                            break  # Exit league loop after showing live games
            
            if live_game_shown:
                continue  # Skip normal rotation and check for live games again

            mode = controller.available_modes[controller.current_mode_index]
            duration = controller.config.get("display", {}).get("display_durations", {}).get(mode.split("_")[-1], 10)

            logger.info(f"Displaying mode: {mode} for {duration} seconds")

            # Fade out current mode
            controller.run_transition("before")

            if mode == "clock" and controller.clock:
                controller.clock.display_time()
                time.sleep(duration)

            elif mode.endswith("_leaderboard"):
                league = mode.split("_")[0]
                controller.league_managers[league]["leaderboard"].display()

            elif mode.endswith("_recent"):
                league = mode.split("_")[0]
                mgr = controller.league_managers[league]["recent"]
                mgr.update()
                start = time.time()
                while time.time() - start < duration * mgr.recent_games_to_show:
                    mgr.display()
                    time.sleep(1)

            elif mode.endswith("_upcoming"):
                league = mode.split("_")[0]
                mgr = controller.league_managers[league]["upcoming"]
                mgr.update()
                start = time.time()
                while time.time() - start < duration * mgr.upcoming_games_to_show:
                    mgr.display()
                    time.sleep(1)

            elif mode == "sponsors" and controller.sponsors:
                # Get batch of sponsors to display
                sponsors_to_show = controller.sponsors.get_next_sponsors()
                
                if sponsors_to_show:
                    cfg = controller.config.get("sponsors", {})
                    
                    # Show title slide once at the beginning
                    controller.sponsors.render_title()
                    time.sleep(cfg.get("title_duration", 5))
                    
                    # Loop through each sponsor in the batch
                    for sponsor in sponsors_to_show:
                        # Show logo
                        controller.sponsors.render_logo(sponsor)
                        time.sleep(cfg.get("logo_duration", 10))
                        
                        # Show details if enabled
                        details_dur = controller.sponsors.render_details(sponsor)
                        if details_dur > 0:
                            time.sleep(details_dur)
                        
            elif mode == "team_info":
                cfg = controller.config.get("team_info", {})
                controller.display_manager.render_team_info(cfg)
                #time.sleep(cfg.get("slide3_duration", 10))

            controller.run_transition("after")
            
            # Move to next mode
            controller.current_mode_index = (controller.current_mode_index + 1) % len(controller.available_modes)

    except KeyboardInterrupt:
        logger.info("Shutting down display loop gracefully")

if __name__ == "__main__":
    main()