"""Episode checker for detecting and downloading new episodes automatically"""
import logging
from typing import List, Optional, Dict
from datetime import datetime

from app.watchlist import watchlist_manager, WatchlistManager
from app.models import DownloadRequest, DownloadTask, DownloadStatus
from app.models.watchlist import (
    WatchlistItem,
    WatchlistSettings,
    NewEpisodeInfo,
    AutoDownloadResult
)

logger = logging.getLogger(__name__)


class EpisodeChecker:
    """Checks for new episodes and downloads them automatically"""

    def __init__(self, wlm: Optional[WatchlistManager] = None):
        self.wlm = wlm or watchlist_manager
        self.download_manager = None  # Will be set by main.py

    def set_download_manager(self, download_manager):
        """Set the download manager (called by main.py to avoid circular import)"""
        self.download_manager = download_manager

    async def check_anime(self, item: WatchlistItem) -> List[NewEpisodeInfo]:
        """
        Check for new episodes of a specific anime

        Args:
            item: WatchlistItem to check

        Returns:
            List of NewEpisodeInfo objects
        """
        try:
            logger.info(f"Checking for new episodes: {item.anime_title}")

            # Import here to avoid circular imports
            from app.downloaders import get_downloader
            from urllib.parse import unquote

            # Decode URL if it's encoded (handles double-encoded URLs)
            anime_url = item.anime_url
            try:
                # Try to decode - if already decoded, this will be a no-op
                decoded_url = unquote(anime_url)
                # Handle double encoding
                if '%' in decoded_url:
                    decoded_url = unquote(decoded_url)
                anime_url = decoded_url
            except Exception as e:
                logger.warning(f"Could not decode URL: {e}, using original")

            # Get the appropriate downloader
            downloader = get_downloader(anime_url)
            if not downloader:
                logger.error(f"No downloader found for URL: {anime_url}")
                return []

            # Get episodes list
            episodes = await downloader.get_episodes(anime_url, item.lang)
            if not episodes:
                logger.warning(f"No episodes found for {item.anime_title}")
                return []

            # Filter new episodes
            new_episodes = []
            for ep in episodes:
                # Handle both 'episode' (from anime-sama) and 'episode_number' keys
                ep_num_raw = ep.get('episode_number') or ep.get('episode')
                # Convert to int (handles string episode numbers like "01", "02")
                try:
                    ep_num = int(str(ep_num_raw).lstrip('0') or '0')
                except (ValueError, TypeError):
                    ep_num = 0

                if ep_num > item.last_episode_downloaded:
                    new_episodes.append(NewEpisodeInfo(
                        episode_number=ep_num,
                        episode_title=ep.get('title'),
                        episode_url=ep['url'],
                        season_number=ep.get('season'),
                        anime_title=item.anime_title,
                        provider_id=item.provider_id
                    ))

            if new_episodes:
                logger.info(f"Found {len(new_episodes)} new episodes for {item.anime_title}")
            else:
                logger.info(f"No new episodes for {item.anime_title}")

            return new_episodes

        except Exception as e:
            logger.error(f"Error checking anime {item.anime_title}: {e}", exc_info=True)
            return []

    async def download_new_episodes(
        self,
        item: WatchlistItem,
        episodes: List[NewEpisodeInfo]
    ) -> AutoDownloadResult:
        """
        Download new episodes for a watchlist item

        Args:
            item: WatchlistItem
            episodes: List of new episodes to download

        Returns:
            AutoDownloadResult with download status
        """
        result = AutoDownloadResult(
            watchlist_item_id=item.id,
            anime_title=item.anime_title,
            new_episodes_found=len(episodes),
            checked_at=datetime.now()
        )

        if not episodes:
            return result

        # Get settings
        settings = self.wlm.get_settings()
        if not settings.auto_download_enabled:
            logger.info(f"Auto-download disabled, skipping {len(episodes)} episodes")
            return result

        try:
            # Import here to avoid circular imports
            from app.downloaders import get_downloader
            from urllib.parse import unquote

            # Decode URL if it's encoded
            anime_url = item.anime_url
            try:
                decoded_url = unquote(anime_url)
                if '%' in decoded_url:
                    decoded_url = unquote(decoded_url)
                anime_url = decoded_url
            except Exception:
                pass

            downloader = get_downloader(anime_url)

            # Download each new episode
            for ep_info in episodes:
                try:
                    logger.info(f"Downloading {item.anime_title} Episode {ep_info.episode_number}")

                    # Get download link - episode_url may be pipe-separated with multiple sources
                    download_link, filename = await downloader.get_download_link(ep_info.episode_url)

                    # Create download task
                    request = DownloadRequest(url=download_link, filename=filename)
                    task = self.download_manager.create_task(request)
                    
                    if task:
                        await self.download_manager.start_download(task.id)
                        result.episodes_downloaded.append(ep_info.episode_number)
                        logger.info(f"Started download: {filename}")
                    else:
                        result.episodes_failed.append((ep_info.episode_number, "Failed to create download task"))

                except Exception as e:
                    error_msg = str(e)
                    logger.error(f"Error downloading episode {ep_info.episode_number}: {error_msg}")
                    result.episodes_failed.append((ep_info.episode_number, error_msg))

            # Update watchlist with last episode downloaded
            if result.episodes_downloaded:
                last_ep = max(result.episodes_downloaded)
                self.wlm.update_check_time(item.id, last_ep)

        except Exception as e:
            logger.error(f"Error in download_new_episodes: {e}", exc_info=True)

        return result

    async def check_and_download(self, item: WatchlistItem) -> AutoDownloadResult:
        """
        Check for new episodes and download them if auto_download is enabled

        Args:
            item: WatchlistItem to check

        Returns:
            AutoDownloadResult
        """
        # Check for new episodes
        new_episodes = await self.check_anime(item)

        result = AutoDownloadResult(
            watchlist_item_id=item.id,
            anime_title=item.anime_title,
            new_episodes_found=len(new_episodes),
            checked_at=datetime.now()
        )

        # Download if auto_download is enabled
        if item.auto_download and new_episodes:
            settings = self.wlm.get_settings()
            if settings.auto_download_enabled:
                download_result = await self.download_new_episodes(item, new_episodes)
                result = download_result
            else:
                logger.info(f"Auto-download globally disabled, skipping {len(new_episodes)} episodes")

        # Update check time even if no downloads
        self.wlm.update_check_time(item.id, item.last_episode_downloaded)

        return result

    async def check_all_due(self) -> List[AutoDownloadResult]:
        """
        Check all watchlist items that are due for checking

        Returns:
            List of AutoDownloadResult objects
        """
        settings = self.wlm.get_settings()
        due_items = self.wlm.get_due_for_check(settings.check_interval_hours)

        logger.info(f"Checking {len(due_items)} due watchlist items")

        results = []
        for item in due_items:
            try:
                result = await self.check_and_download(item)
                results.append(result)
            except Exception as e:
                logger.error(f"Error processing {item.anime_title}: {e}", exc_info=True)
                # Still add a result to track the failure
                results.append(AutoDownloadResult(
                    watchlist_item_id=item.id,
                    anime_title=item.anime_title,
                    new_episodes_found=0,
                    checked_at=datetime.now()
                ))

        # Log summary
        total_new = sum(r.new_episodes_found for r in results)
        total_downloaded = sum(len(r.episodes_downloaded) for r in results)
        total_failed = sum(len(r.episodes_failed) for r in results)

        logger.info(
            f"Check complete: {total_new} new episodes found, "
            f"{total_downloaded} downloaded, {total_failed} failed"
        )

        return results

    async def manual_check(self, item_id: str) -> Optional[AutoDownloadResult]:
        """
        Manually trigger a check for a specific watchlist item

        Args:
            item_id: Watchlist item ID

        Returns:
            AutoDownloadResult or None if item not found
        """
        item = self.wlm.get_by_id(item_id)
        if not item:
            logger.error(f"Watchlist item not found: {item_id}")
            return None

        return await self.check_and_download(item)


# Global episode checker instance
episode_checker = EpisodeChecker()
