"""
Platforms Router

Handles platform management operations:
- List all platforms and their status
- Trigger manual downloads for platforms
- Instagram-specific post downloads
"""

import asyncio
import re
import shutil
import tempfile
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional

from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException, Request
from pydantic import BaseModel
from slowapi import Limiter
from slowapi.util import get_remote_address

from ..core.dependencies import get_current_user, get_app_state
from ..core.exceptions import handle_exceptions, ValidationError
from ..core.responses import now_iso8601
from modules.universal_logger import get_logger

logger = get_logger('API')

router = APIRouter(prefix="/api", tags=["Platforms"])
limiter = Limiter(key_func=get_remote_address)

# Semaphore to limit concurrent Instagram post downloads to 1
_instagram_post_semaphore = asyncio.Semaphore(1)
_instagram_post_queue: List[str] = []  # Track queued posts for status


# ============================================================================
# PYDANTIC MODELS
# ============================================================================

class TriggerRequest(BaseModel):
    username: Optional[str] = None
    content_types: Optional[List[str]] = None


class InstagramPostRequest(BaseModel):
    post_id: str
    username: Optional[str] = None


# ============================================================================
# DOWNLOAD CACHE UTILITIES
# ============================================================================

def invalidate_download_cache():
    """Invalidate download-related caches after downloads complete."""
    from ..core.dependencies import get_app_state
    app_state = get_app_state()
    if hasattr(app_state, 'cache') and app_state.cache:
        try:
            app_state.cache.invalidate_pattern('downloads:*')
            app_state.cache.invalidate_pattern('stats:*')
            app_state.cache.invalidate_pattern('gallery:*')
        except Exception:
            pass


# ============================================================================
# PLATFORM STATUS ENDPOINTS
# ============================================================================

@router.get("/platforms/running")
@limiter.limit("100/minute")
@handle_exceptions
async def get_running_platforms(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get list of currently running platform downloads"""
    app_state = get_app_state()

    running = []
    if hasattr(app_state, 'running_platform_downloads'):
        for platform, data in app_state.running_platform_downloads.items():
            running.append({
                'platform': platform,
                'started_at': data.get('started_at'),
                'session_id': data.get('session_id')
            })

    return {
        "platforms": running,
        "count": len(running)
    }


@router.post("/platforms/{platform}/stop")
@limiter.limit("10/minute")
@handle_exceptions
async def stop_platform_download(
    request: Request,
    platform: str,
    current_user: Dict = Depends(get_current_user)
):
    """Stop a running platform download"""
    app_state = get_app_state()

    if not hasattr(app_state, 'running_platform_downloads'):
        raise HTTPException(status_code=404, detail="No running downloads found")

    if platform not in app_state.running_platform_downloads:
        raise HTTPException(status_code=404, detail=f"Platform {platform} is not running")

    download_data = app_state.running_platform_downloads[platform]
    process = download_data.get('process')
    session_id = download_data.get('session_id')

    if process:
        try:
            import subprocess

            # Get the process ID
            pid = process.pid
            logger.info(f"Stopping {platform} download (PID: {pid})", module="Platforms")

            # Kill all child processes first using pkill
            try:
                result = subprocess.run(['pkill', '-9', '-P', str(pid)],
                                      capture_output=True, timeout=2)
                logger.info(f"Killed child processes of PID {pid}", module="Platforms")
            except subprocess.TimeoutExpired:
                logger.warning(f"pkill timed out for PID {pid}, continuing", module="Platforms")
            except Exception as pkill_error:
                logger.warning(f"pkill failed for PID {pid}: {pkill_error}, continuing", module="Platforms")

            # Give processes time to die
            await asyncio.sleep(0.5)

            # Then kill the parent process
            try:
                process.kill()
                await asyncio.wait_for(process.wait(), timeout=5.0)
                logger.info(f"Stopped {platform} download successfully", module="Platforms")
            except asyncio.TimeoutError:
                logger.warning(f"Process {pid} did not terminate in time", module="Platforms")
            except ProcessLookupError:
                logger.info(f"Process {pid} already terminated", module="Platforms")

        except Exception as e:
            error_msg = str(e) if str(e) else repr(e)
            logger.error(f"Error stopping {platform} download: {error_msg}", module="Platforms", exc_info=True)
            raise HTTPException(status_code=500, detail=f"Failed to stop download: {error_msg}")

    # Remove from tracking
    app_state.running_platform_downloads.pop(platform, None)

    # Clean up scraper session if it exists
    if session_id and hasattr(app_state, 'active_scraper_sessions'):
        app_state.active_scraper_sessions.pop(session_id, None)

    # Emit scraper_completed event to update frontend
    if session_id and hasattr(app_state, 'scraper_event_emitter') and app_state.scraper_event_emitter:
        app_state.scraper_event_emitter.emit_scraper_completed(
            session_id=session_id,
            stats={
                'total_downloaded': 0,
                'moved': 0,
                'review': 0,
                'duplicates': 0,
                'failed': 0
            }
        )

    return {
        "success": True,
        "platform": platform,
        "message": f"{platform} download stopped"
    }


# ============================================================================
# SCRAPER MONITOR ENDPOINTS
# ============================================================================

@router.get("/scraper-sessions/active")
@limiter.limit("100/minute")
@handle_exceptions
async def get_active_scraper_sessions(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get currently active scraping sessions for the scraping monitor page"""
    app_state = get_app_state()

    # Return active sessions from app_state
    sessions = app_state.active_scraper_sessions if hasattr(app_state, 'active_scraper_sessions') else {}

    return {
        "sessions": list(sessions.values()),
        "count": len(sessions)
    }


# ============================================================================
# PLATFORM LIST ENDPOINT
# ============================================================================

@router.get("/platforms")
@limiter.limit("100/minute")
@handle_exceptions
async def get_platforms(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get list of all platforms and their status."""
    app_state = get_app_state()
    config = app_state.settings.get_all() if app_state.settings else app_state.config
    platforms = []

    display_names = {
        'instagram_unified': 'Instagram',
        'snapchat': 'Snapchat',
        'snapchat_client': 'Snapchat',
        'tiktok': 'TikTok',
        'forums': 'Forums',
        'coppermine': 'Coppermine',
    }

    hidden_modules = config.get('hidden_modules', [])

    for platform_name in ['instagram_unified', 'snapchat', 'snapchat_client', 'tiktok', 'forums', 'coppermine']:
        if platform_name in hidden_modules:
            continue
        platform_config = config.get(platform_name, {})
        enabled = platform_config.get('enabled', False)

        check_interval = None
        if platform_name == 'instagram_unified':
            accounts = platform_config.get('accounts', [])
            if accounts:
                check_interval = accounts[0].get('check_interval_hours')
        elif platform_name == 'tiktok':
            accounts = platform_config.get('accounts', [])
            if accounts:
                check_interval = accounts[0].get('check_interval_hours')
        elif platform_name == 'forums':
            configs = platform_config.get('configs', [])
            if configs:
                check_interval = configs[0].get('check_interval_hours')
        elif platform_name == 'coppermine':
            check_interval = platform_config.get('check_interval_hours')
        else:
            check_interval = platform_config.get('check_interval_hours')

        account_count = 0
        if platform_name == 'instagram_unified':
            account_count = len(platform_config.get('accounts', []))
        elif platform_name in ['snapchat', 'snapchat_client']:
            account_count = len(platform_config.get('usernames', []))
        elif platform_name == 'tiktok':
            account_count = len(platform_config.get('accounts', []))
        elif platform_name == 'forums':
            account_count = len(platform_config.get('configs', []))
        elif platform_name == 'coppermine':
            account_count = len(platform_config.get('galleries', []))

        platforms.append({
            "name": platform_name,
            "type": "scheduled",
            "enabled": enabled,
            "display_name": display_names.get(platform_name, platform_name.title()),
            "check_interval_hours": check_interval,
            "account_count": account_count,
            "config": platform_config
        })

    logger.info(f"Returning {len(platforms)} scheduled platforms", module="Platforms")
    return platforms


# ============================================================================
# TRIGGER PLATFORM DOWNLOAD
# ============================================================================

@router.post("/platforms/{platform}/trigger")
@limiter.limit("10/minute")
@handle_exceptions
async def trigger_platform_download(
    request: Request,
    platform: str,
    trigger_data: TriggerRequest,
    background_tasks: BackgroundTasks,
    current_user: Dict = Depends(get_current_user)
):
    """Manually trigger a download for a platform."""
    valid_platforms = ['instagram_unified', 'fastdl', 'imginn', 'imginn_api', 'instagram_client', 'toolzu', 'snapchat', 'snapchat_client', 'tiktok', 'forums', 'coppermine']
    if platform not in valid_platforms:
        raise ValidationError(f"Invalid platform: {platform}")

    app_state = get_app_state()
    task_id = f"{platform}_{datetime.now().timestamp()}"

    async def run_download():
        try:
            session_id = f"{platform}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"

            # Get list of accounts/forums to process
            accounts_to_process = []

            # For forums, get ALL enabled forum names
            if platform == 'forums':
                forums_config = app_state.settings.get('forums', {})
                for forum_cfg in forums_config.get('configs', []):
                    if forum_cfg.get('enabled', False):
                        accounts_to_process.append(forum_cfg.get('name', 'Unknown'))

            # For Coppermine, get ALL galleries
            elif platform == 'coppermine':
                coppermine_config = app_state.settings.get('coppermine', {})
                for gallery in coppermine_config.get('galleries', []):
                    gallery_name = gallery.get('name', 'Unknown')
                    accounts_to_process.append(gallery_name)

            # For Instagram unified, get all accounts from unified config
            elif platform == 'instagram_unified':
                unified_config = app_state.settings.get('instagram_unified', {})
                for acc in unified_config.get('accounts', []):
                    if acc.get('username'):
                        accounts_to_process.append(acc['username'])

            # For other platforms, get ALL usernames
            elif platform in ['fastdl', 'imginn', 'imginn_api', 'instagram_client', 'toolzu', 'snapchat']:
                platform_config = app_state.settings.get(platform, {})
                accounts_to_process = platform_config.get('usernames', [])

                # For imginn/imginn_api/fastdl/instagram_client, also include phrase search usernames if enabled
                if platform in ['imginn', 'imginn_api', 'fastdl', 'instagram_client']:
                    phrase_config = platform_config.get('phrase_search', {})
                    if phrase_config.get('enabled'):
                        phrase_usernames = phrase_config.get('usernames', [])
                        # Add phrase search users to the list
                        accounts_to_process.extend(phrase_usernames)

            # For TikTok, get ALL accounts
            elif platform == 'tiktok':
                tiktok_config = app_state.settings.get('tiktok', {})
                accounts = tiktok_config.get('accounts', [])
                for acc in accounts:
                    if acc.get('enabled', True):
                        accounts_to_process.append(acc.get('username', 'Unknown'))

            # Emit ONE scraper_started event with the complete list
            # Map Instagram downloaders to "Instagram" for display
            display_platform = platform
            if platform in ['instagram_unified', 'fastdl', 'imginn', 'imginn_api', 'instagram_client', 'toolzu', 'instaloader']:
                display_platform = 'Instagram'

            if app_state.scraper_event_emitter:
                app_state.scraper_event_emitter.emit_scraper_started(
                    session_id=session_id,
                    platform=display_platform,
                    account='all',  # Match scheduler format
                    content_type="auto",
                    estimated_count=len(accounts_to_process),
                    accounts_list=accounts_to_process  # Pass the full list
                )

            cmd = ["media-downloader", "--platform", platform]

            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )

            # Track running process in app_state
            if hasattr(app_state, 'running_platform_downloads'):
                app_state.running_platform_downloads[platform] = {
                    'process': process,
                    'started_at': datetime.now().isoformat(),
                    'session_id': session_id
                }

            manager = getattr(app_state, 'websocket_manager', None)

            # Track progress by parsing log output
            # Note: Universal logger's console handler writes to stderr, not stdout
            current_account = None
            processed_count = 0  # Track how many accounts we've processed sequentially
            completed_accounts = []  # Track accounts that have finished processing
            if manager:
                async for line in process.stderr:
                    line_text = line.decode().strip()

                    # Broadcast log message
                    await manager.broadcast({
                        "type": "log",
                        "level": "info",
                        "message": line_text,
                        "platform": display_platform
                    })

                    # Parse log to detect current forum/account being processed
                    if app_state.scraper_event_emitter and accounts_to_process:
                        import re

                        # Detect forum processing - match exact format: "Processing forum: ForumName"
                        if 'Processing forum:' in line_text:
                            forum_match = re.search(r'Processing forum:\s+(.+)', line_text)
                            if forum_match:
                                detected_forum = forum_match.group(1).strip()
                                logger.debug(f"Detected forum from log: '{detected_forum}'", module="ScrapingMonitor")
                                # Find matching account in our list
                                for account in accounts_to_process:
                                    logger.debug(f"Comparing '{detected_forum.lower()}' with '{account.lower()}'", module="ScrapingMonitor")
                                    if account.lower() in detected_forum.lower() or detected_forum.lower() in account.lower():
                                        if current_account != account:
                                            # Mark previous account as completed
                                            if current_account and current_account not in completed_accounts:
                                                completed_accounts.append(current_account)
                                            current_account = account
                                            processed_count += 1
                                            logger.info(f"Forum progress: Now processing {account} ({processed_count}/{len(accounts_to_process)})", module="ScrapingMonitor")
                                            app_state.scraper_event_emitter.emit_scraper_progress(
                                                session_id=session_id,
                                                status=f"Checking forum thread: {account}",
                                                current=processed_count,
                                                total=len(accounts_to_process),
                                                current_account=account,
                                                completed_accounts=completed_accounts
                                            )
                                        break

                        # Detect Coppermine gallery processing - match exact format: "Processing Coppermine gallery: GalleryName"
                        elif 'Processing Coppermine gallery:' in line_text:
                            gallery_match = re.search(r'Processing Coppermine gallery:\s+(.+)', line_text)
                            if gallery_match:
                                detected_gallery = gallery_match.group(1).strip()
                                # Find matching gallery in our list
                                for account in accounts_to_process:
                                    if account.lower() in detected_gallery.lower() or detected_gallery.lower() in account.lower():
                                        if current_account != account:
                                            # Mark previous account as completed
                                            if current_account and current_account not in completed_accounts:
                                                completed_accounts.append(current_account)
                                            current_account = account
                                            processed_count += 1
                                            logger.info(f"Coppermine progress: Now processing {account} ({processed_count}/{len(accounts_to_process)})", module="ScrapingMonitor")
                                            app_state.scraper_event_emitter.emit_scraper_progress(
                                                session_id=session_id,
                                                status=f"Checking gallery: {account}",
                                                current=processed_count,
                                                total=len(accounts_to_process),
                                                current_account=account,
                                                completed_accounts=completed_accounts
                                            )
                                        break

                        # Detect TikTok user processing (format: "Downloading TikTok profile: @username")
                        elif 'Downloading TikTok profile: @' in line_text:
                            user_match = re.search(r'Downloading TikTok profile: @([a-zA-Z0-9_.]+)', line_text)
                            if user_match:
                                detected_user = user_match.group(1)
                                # Find matching account in our list
                                for account in accounts_to_process:
                                    if account.lower() == detected_user.lower():
                                        if current_account != account:
                                            # Mark previous account as completed
                                            if current_account and current_account not in completed_accounts:
                                                completed_accounts.append(current_account)
                                            current_account = account
                                            processed_count += 1
                                            logger.info(f"TikTok progress: Now processing {account} ({processed_count}/{len(accounts_to_process)})", module="ScrapingMonitor")
                                            app_state.scraper_event_emitter.emit_scraper_progress(
                                                session_id=session_id,
                                                status=f"Checking videos from @{account}",
                                                current=processed_count,
                                                total=len(accounts_to_process),
                                                current_account=account,
                                                completed_accounts=completed_accounts
                                            )
                                        break

                        # Detect Snapchat user processing (format: "Navigating to @username on domain")
                        elif 'Navigating to @' in line_text:
                            user_match = re.search(r'Navigating to @([a-zA-Z0-9_.]+)', line_text)
                            if user_match:
                                detected_user = user_match.group(1)
                                # Find matching account in our list
                                for account in accounts_to_process:
                                    if account.lower() == detected_user.lower():
                                        if current_account != account:
                                            # Mark previous account as completed
                                            if current_account and current_account not in completed_accounts:
                                                completed_accounts.append(current_account)
                                            current_account = account
                                            processed_count += 1
                                            logger.info(f"Snapchat progress: Now processing {account} ({processed_count}/{len(accounts_to_process)})", module="ScrapingMonitor")
                                            app_state.scraper_event_emitter.emit_scraper_progress(
                                                session_id=session_id,
                                                status=f"Checking stories from @{account}",
                                                current=processed_count,
                                                total=len(accounts_to_process),
                                                current_account=account,
                                                completed_accounts=completed_accounts
                                            )
                                        break

                        # Detect Instagram/FastDL user processing (format: "Processing Instagram {content_type} for @username")
                        elif 'Processing Instagram' in line_text and 'for @' in line_text:
                            user_match = re.search(r'Processing Instagram (\w+) for @([a-zA-Z0-9_.]+)', line_text)
                            if user_match:
                                content_type = user_match.group(1)  # posts, stories, reels, tagged
                                detected_user = user_match.group(2)
                                # Find matching account in our list
                                for account in accounts_to_process:
                                    if account.lower() == detected_user.lower():
                                        if current_account != account:
                                            # Mark previous account as completed
                                            if current_account and current_account not in completed_accounts:
                                                completed_accounts.append(current_account)
                                            current_account = account
                                            processed_count += 1
                                            logger.info(f"FastDL/Instagram progress: Now processing {account} ({processed_count}/{len(accounts_to_process)})", module="ScrapingMonitor")

                                        # Always update status with current content type
                                        status_msg = f"Checking {content_type} from @{account}"

                                        app_state.scraper_event_emitter.emit_scraper_progress(
                                            session_id=session_id,
                                            status=status_msg,
                                            current=processed_count,
                                            total=len(accounts_to_process),
                                            current_account=account,
                                            completed_accounts=completed_accounts
                                        )
                                        break

                        # Detect phrase search user processing (format: "Searching username for phrase matches")
                        elif 'for phrase matches' in line_text:
                            user_match = re.search(r'Searching ([a-zA-Z0-9_.]+) for phrase matches', line_text)
                            if user_match:
                                detected_user = user_match.group(1)
                                # Find matching account in our list
                                for account in accounts_to_process:
                                    if account.lower() == detected_user.lower():
                                        if current_account != account:
                                            # Mark previous account as completed
                                            if current_account and current_account not in completed_accounts:
                                                completed_accounts.append(current_account)
                                            current_account = account
                                            processed_count += 1
                                            logger.info(f"Phrase search progress: Now processing {account} ({processed_count}/{len(accounts_to_process)})", module="ScrapingMonitor")
                                            app_state.scraper_event_emitter.emit_scraper_progress(
                                                session_id=session_id,
                                                status=f"Searching phrases in: {account}",
                                                current=processed_count,
                                                total=len(accounts_to_process),
                                                current_account=account,
                                                completed_accounts=completed_accounts
                                            )
                                        break

            await process.wait()
            invalidate_download_cache()

            # Remove from running downloads
            if hasattr(app_state, 'running_platform_downloads'):
                app_state.running_platform_downloads.pop(platform, None)

            # Emit scraper_completed event once for the whole platform
            if app_state.scraper_event_emitter:
                app_state.scraper_event_emitter.emit_scraper_completed(
                    session_id=session_id,
                    stats={
                        'total_downloaded': 0,  # CLI doesn't report this
                        'moved': 0,
                        'review': 0,
                        'duplicates': 0,
                        'failed': 0 if process.returncode == 0 else 1
                    }
                )

            if manager:
                await manager.broadcast({
                    "type": "download_completed",
                    "platform": display_platform,
                    "username": trigger_data.username or "all",
                    "exit_code": process.returncode,
                    "timestamp": now_iso8601(),
                    "from_platform_page": True
                })

        except Exception as e:
            # Remove from running downloads
            if hasattr(app_state, 'running_platform_downloads'):
                app_state.running_platform_downloads.pop(platform, None)

            # Emit scraper_completed event with error
            if app_state.scraper_event_emitter:
                app_state.scraper_event_emitter.emit_scraper_completed(
                    session_id=session_id,
                    stats={
                        'total_downloaded': 0,
                        'moved': 0,
                        'review': 0,
                        'duplicates': 0,
                        'failed': 1
                    }
                )

            manager = getattr(app_state, 'websocket_manager', None)
            if manager:
                await manager.broadcast({
                    "type": "download_error",
                    "platform": platform,
                    "error": str(e),
                    "timestamp": now_iso8601()
                })

    background_tasks.add_task(run_download)

    return {
        "success": True,
        "task_id": task_id,
        "platform": platform,
        "message": f"Download triggered for {platform}"
    }


# ============================================================================
# INSTAGRAM POST DOWNLOAD
# ============================================================================

@router.post("/instagram/download-post")
@limiter.limit("20/minute")
@handle_exceptions
async def download_instagram_post(
    request: Request,
    background_tasks: BackgroundTasks,
    current_user: Dict = Depends(get_current_user),
    post_id: str = Body(..., description="Instagram post shortcode or full URL"),
    username: str = Body(None, description="Username (optional)")
):
    """Download a specific Instagram post using ImgInn and process through move manager."""
    app_state = get_app_state()

    # Extract shortcode from URL if full URL provided
    shortcode = post_id
    if 'instagram.com' in post_id or 'imginn.com' in post_id:
        match = re.search(r'/p/([A-Za-z0-9_-]+)', post_id)
        if match:
            shortcode = match.group(1)
        else:
            raise ValidationError("Could not extract post ID from URL")

    # Check if already downloaded
    with app_state.db.get_connection() as conn:
        cursor = conn.cursor()
        cursor.execute('''
            SELECT id, filename, file_path FROM downloads
            WHERE media_id = ? AND platform = 'instagram'
        ''', (shortcode,))
        existing = cursor.fetchone()
        if existing and existing['file_path']:
            if Path(existing['file_path']).exists():
                return {
                    "success": False,
                    "message": f"Post {shortcode} already downloaded",
                    "filename": existing['filename'],
                    "file_path": existing['file_path']
                }

    task_id = f"instagram_post_{shortcode}_{datetime.now().timestamp()}"

    async def run_post_download():
        # Add to queue tracking
        _instagram_post_queue.append(shortcode)
        queue_position = len(_instagram_post_queue)

        # Wait for semaphore (only 1 download at a time)
        async with _instagram_post_semaphore:
            try:
                from modules.activity_status import get_activity_manager
                activity_manager = get_activity_manager(app_state.db)

                activity_manager.start_activity(
                    task_id=task_id,
                    platform='instagram',
                    account=username if username else f'post {shortcode}',
                    status='Downloading post'
                )
                activity_manager.update_status(f"Fetching post {shortcode}...")

                manager = getattr(app_state, 'websocket_manager', None)
                if manager:
                    await manager.broadcast({
                        "type": "download_started",
                        "platform": "instagram",
                        "username": username or f"post/{shortcode}",
                        "post_id": shortcode,
                        "timestamp": now_iso8601()
                    })

                import concurrent.futures

                def do_download():
                    from modules.imginn_module import ImgInnDownloader
                    from modules.move_module import MoveManager

                    imginn_config = app_state.settings.get('imginn', {})
                    posts_config = imginn_config.get('posts', {})
                    dest_path = posts_config.get('destination_path')

                    if not dest_path:
                        dest_path = "/opt/immich/md/social media/instagram/posts"
                        logger.warning("ImgInn posts destination not configured, using default", module="Instagram")

                    dest_base = Path(dest_path)
                    dest_base.mkdir(parents=True, exist_ok=True)

                    temp_dir = Path(tempfile.mkdtemp(prefix='instagram_post_'))

                    try:
                        from datetime import datetime

                        downloader = ImgInnDownloader(unified_db=app_state.db)
                        post_url = f"https://imginn.com/p/{shortcode}/"
                        target_username = username or 'unknown'

                        # Generate session ID for tracking
                        session_id = f"imginn_{target_username}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"

                        # Emit scraper_started event
                        if app_state.scraper_event_emitter:
                            app_state.scraper_event_emitter.emit_scraper_started(
                                session_id=session_id,
                                platform='instagram',
                                account=target_username,
                                content_type='post',
                                estimated_count=1
                            )

                        downloaded = downloader.download_posts(
                            username=target_username,
                            specific_post_url=post_url,
                            output_dir=temp_dir,
                            days_back=365,
                            max_posts=1
                        )

                        if not downloaded:
                            return {"success": False, "message": "No files downloaded"}

                        if target_username == 'unknown' and downloaded:
                            first_file = Path(downloaded[0])
                            parts = first_file.stem.split('_')
                            if parts:
                                target_username = parts[0]

                        move_manager = MoveManager(
                            unified_db=app_state.db,
                            event_emitter=app_state.scraper_event_emitter
                        )

                        # Set session context for real-time monitoring (use session_id from above)
                        move_manager.set_session_context(
                            platform='instagram',
                            account=target_username,
                            session_id=session_id
                        )

                        moved_files = []
                        # Create username subdirectory
                        user_dest = dest_base / target_username
                        user_dest.mkdir(parents=True, exist_ok=True)

                        for file_path in downloaded:
                            src = Path(file_path)
                            if src.exists():
                                dest = user_dest / src.name

                                move_manager.start_batch(
                                    platform='instagram',
                                    source=target_username,
                                    content_type='post'
                                )

                                success = move_manager.move_file(src, dest)
                                if success:
                                    moved_files.append(str(dest))

                                move_manager.end_batch()

                        # Emit scraper_completed event
                        if app_state.scraper_event_emitter:
                            app_state.scraper_event_emitter.emit_scraper_completed(
                                session_id=session_id,
                                stats={
                                    'total_downloaded': len(downloaded),
                                    'moved': len(moved_files),
                                    'review': 0,  # Would need to track separately
                                    'duplicates': 0,  # Would need to track separately
                                    'failed': len(downloaded) - len(moved_files)
                                }
                            )

                        return {
                            "success": True,
                            "message": f"Downloaded and processed {len(moved_files)} file(s)",
                            "files": moved_files,
                            "username": target_username
                        }

                    finally:
                        if temp_dir.exists():
                            shutil.rmtree(temp_dir, ignore_errors=True)

                # Use a fresh ThreadPoolExecutor to avoid Playwright sync API issues
                # Playwright detects if there's an event loop in the thread and errors
                loop = asyncio.get_event_loop()
                with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
                    result = await loop.run_in_executor(executor, do_download)
                activity_manager.stop_activity()
                invalidate_download_cache()

                if manager:
                    # Get username from result if available
                    completed_username = result.get('username') if result else None
                    await manager.broadcast({
                        "type": "download_completed",
                        "platform": "instagram",
                        "username": completed_username or username or f"post/{shortcode}",
                        "post_id": shortcode,
                        "result": result,
                        "timestamp": now_iso8601()
                    })

                return result

            except Exception as e:
                logger.error(f"Failed to download Instagram post {shortcode}: {e}")
                import traceback
                traceback.print_exc()

                try:
                    activity_manager.stop_activity()
                except Exception:
                    pass

                manager = getattr(app_state, 'websocket_manager', None)
                if manager:
                    await manager.broadcast({
                        "type": "download_error",
                        "platform": "instagram",
                        "username": username or f"post/{shortcode}",
                        "post_id": shortcode,
                        "error": str(e),
                        "timestamp": now_iso8601()
                    })

            finally:
                # Remove from queue tracking
                if shortcode in _instagram_post_queue:
                    _instagram_post_queue.remove(shortcode)

    background_tasks.add_task(run_post_download)

    return {
        "success": True,
        "task_id": task_id,
        "post_id": shortcode,
        "message": f"Download started for post {shortcode}"
    }


# ============================================================================
# YOUTUBE CHANNEL MONITORS - Global Settings + Channel List
# ============================================================================

class YouTubeMonitorSettingsUpdate(BaseModel):
    """Update global YouTube monitor settings."""
    phrases: Optional[List[str]] = None
    check_interval_hours: Optional[int] = None
    quality: Optional[str] = None
    enabled: Optional[bool] = None
    auto_start_queue: Optional[bool] = None
    notifications_enabled: Optional[bool] = None
    auto_pause_threshold_months: Optional[int] = None
    paused_check_interval_days: Optional[int] = None
    max_results_per_phrase: Optional[int] = None


class YouTubeChannelCreate(BaseModel):
    """Add a YouTube channel to monitor."""
    channel_url: str
    channel_name: Optional[str] = None
    enabled: bool = True


class YouTubeChannelUpdate(BaseModel):
    """Update a YouTube channel."""
    channel_url: Optional[str] = None
    channel_name: Optional[str] = None
    enabled: Optional[bool] = None
    always_active: Optional[bool] = None


@router.get("/platforms/youtube-monitors")
@limiter.limit("100/minute")
@handle_exceptions
async def get_youtube_monitors(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get YouTube monitor global settings and all channels."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    global_settings = monitor.get_global_settings()
    channels = monitor.get_all_channels()

    return {
        "success": True,
        "settings": global_settings,
        "channels": channels,
        "count": len(channels)
    }


@router.put("/platforms/youtube-monitors/settings")
@limiter.limit("30/minute")
@handle_exceptions
async def update_youtube_monitor_settings(
    data: YouTubeMonitorSettingsUpdate,
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Update global YouTube monitor settings (phrases, interval, quality)."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    success = monitor.update_global_settings(
        phrases=data.phrases,
        check_interval_hours=data.check_interval_hours,
        quality=data.quality,
        enabled=data.enabled,
        auto_start_queue=data.auto_start_queue,
        notifications_enabled=data.notifications_enabled,
        auto_pause_threshold_months=data.auto_pause_threshold_months,
        paused_check_interval_days=data.paused_check_interval_days,
        max_results_per_phrase=data.max_results_per_phrase
    )

    updated_settings = monitor.get_global_settings()

    return {
        "success": success,
        "settings": updated_settings,
        "message": "YouTube monitor settings updated successfully"
    }


@router.post("/platforms/youtube-monitors/channels")
@limiter.limit("30/minute")
@handle_exceptions
async def add_youtube_channel(
    data: YouTubeChannelCreate,
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Add a new YouTube channel to monitor."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    logger.info(f"Adding YouTube channel: {data.channel_url}")

    if not data.channel_url:
        logger.error("channel_url is missing")
        raise ValidationError("channel_url is required")

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    try:
        channel_id = monitor.add_channel(
            channel_url=data.channel_url,
            channel_name=data.channel_name,
            enabled=data.enabled
        )
        logger.info(f"Successfully added channel {channel_id}: {data.channel_url}")
    except Exception as e:
        logger.error(f"Error adding channel: {e}")
        if "UNIQUE constraint failed" in str(e):
            raise ValidationError("This channel URL is already being monitored")
        raise

    channel = monitor.get_channel(channel_id)

    return {
        "success": True,
        "channel": channel,
        "message": "YouTube channel added successfully"
    }


@router.put("/platforms/youtube-monitors/channels/{channel_id}")
@limiter.limit("30/minute")
@handle_exceptions
async def update_youtube_channel(
    channel_id: int,
    data: YouTubeChannelUpdate,
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Update a YouTube channel."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    existing = monitor.get_channel(channel_id)
    if not existing:
        raise HTTPException(status_code=404, detail="Channel not found")

    updates = {}
    if data.channel_url is not None:
        updates['channel_url'] = data.channel_url
    if data.channel_name is not None:
        updates['channel_name'] = data.channel_name
    if data.enabled is not None:
        updates['enabled'] = data.enabled

    if updates:
        monitor.update_channel(channel_id, **updates)

    channel = monitor.get_channel(channel_id)

    return {
        "success": True,
        "channel": channel,
        "message": "YouTube channel updated successfully"
    }


@router.delete("/platforms/youtube-monitors/channels/{channel_id}")
@limiter.limit("30/minute")
@handle_exceptions
async def delete_youtube_channel(
    channel_id: int,
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Delete a YouTube channel from monitoring."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    existing = monitor.get_channel(channel_id)
    if not existing:
        raise HTTPException(status_code=404, detail="Channel not found")

    success = monitor.delete_channel(channel_id)

    return {
        "success": success,
        "message": "YouTube channel deleted successfully" if success else "Failed to delete channel"
    }


@router.post("/platforms/youtube-monitors/check-all")
@limiter.limit("5/minute")
@handle_exceptions
async def check_all_youtube_channels(
    request: Request,
    background_tasks: BackgroundTasks,
    current_user: Dict = Depends(get_current_user)
):
    """Trigger an immediate check for all enabled YouTube channels."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from modules.activity_status import get_activity_manager
    from ..core.config import Settings

    settings = Settings()
    app_state = get_app_state()
    activity_manager = get_activity_manager(app_state.db)
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH), activity_manager)

    global_settings = monitor.get_global_settings()
    if not global_settings.get('phrases'):
        raise ValidationError("No match phrases configured. Please add phrases in settings first.")

    channels = monitor.get_enabled_channels()
    if not channels:
        raise ValidationError("No enabled channels to check")

    async def run_check():
        try:
            videos_found = await monitor.check_all_now()
            logger.info(f"YouTube monitor check-all complete: {videos_found} videos found")
        except Exception as e:
            logger.error(f"Error in YouTube monitor check-all: {e}")

    background_tasks.add_task(run_check)

    return {
        "success": True,
        "message": f"Checking {len(channels)} channels...",
        "channels_count": len(channels)
    }


@router.post("/platforms/youtube-monitors/channels/{channel_id}/check-now")
@limiter.limit("10/minute")
@handle_exceptions
async def check_youtube_channel_now(
    channel_id: int,
    request: Request,
    background_tasks: BackgroundTasks,
    current_user: Dict = Depends(get_current_user)
):
    """Trigger an immediate check for a single YouTube channel."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    existing = monitor.get_channel(channel_id)
    if not existing:
        raise HTTPException(status_code=404, detail="Channel not found")

    global_settings = monitor.get_global_settings()
    if not global_settings.get('phrases'):
        raise ValidationError("No match phrases configured. Please add phrases in settings first.")

    async def run_check():
        try:
            videos_found = await monitor.check_single_channel(channel_id)
            logger.info(f"YouTube channel {channel_id} check complete: {videos_found} videos found")
        except Exception as e:
            logger.error(f"Error checking YouTube channel {channel_id}: {e}")

    background_tasks.add_task(run_check)

    return {
        "success": True,
        "message": f"Check started for channel",
        "channel_name": existing.get('channel_name') or existing.get('channel_url')
    }


@router.post("/platforms/youtube-monitors/check-selected")
@limiter.limit("10/minute")
@handle_exceptions
async def check_selected_youtube_channels(
    request: Request,
    background_tasks: BackgroundTasks,
    channel_ids: list[int] = Body(..., embed=True),
    current_user: Dict = Depends(get_current_user)
):
    """Trigger an immediate check for selected YouTube channels."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    global_settings = monitor.get_global_settings()
    if not global_settings.get('phrases'):
        raise ValidationError("No match phrases configured. Please add phrases in settings first.")

    # Validate all channels exist
    for channel_id in channel_ids:
        existing = monitor.get_channel(channel_id)
        if not existing:
            raise HTTPException(status_code=404, detail=f"Channel {channel_id} not found")

    async def run_checks():
        try:
            for channel_id in channel_ids:
                try:
                    videos_found = await monitor.check_single_channel(channel_id)
                    logger.info(f"YouTube channel {channel_id} check complete: {videos_found} videos found")
                except Exception as e:
                    logger.error(f"Error checking YouTube channel {channel_id}: {e}")
        except Exception as e:
            logger.error(f"Error in batch channel check: {e}")

    background_tasks.add_task(run_checks)

    return {
        "success": True,
        "message": f"Check started for {len(channel_ids)} channel(s)",
        "channel_count": len(channel_ids)
    }


@router.get("/platforms/youtube-monitors/channels/{channel_id}/history")
@limiter.limit("100/minute")
@handle_exceptions
async def get_youtube_channel_history(
    channel_id: int,
    request: Request,
    limit: int = 50,
    current_user: Dict = Depends(get_current_user)
):
    """Get history for a YouTube channel."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    existing = monitor.get_channel(channel_id)
    if not existing:
        raise HTTPException(status_code=404, detail="Channel not found")

    history = monitor.get_channel_history(channel_id, limit)

    return {
        "success": True,
        "history": history,
        "count": len(history)
    }


@router.get("/platforms/youtube-monitors/history")
@limiter.limit("100/minute")
@handle_exceptions
async def get_all_youtube_history(
    request: Request,
    limit: int = 100,
    current_user: Dict = Depends(get_current_user)
):
    """Get combined history for all YouTube channels."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    history = monitor.get_all_history(limit)

    return {
        "success": True,
        "history": history,
        "count": len(history)
    }


# ============================================================================
# YOUTUBE CHANNEL MONITORS - v11.20.0 Status Management
# ============================================================================

@router.get("/platforms/youtube-monitors/channels")
@limiter.limit("300/minute")
@handle_exceptions
async def get_youtube_channels_filtered(
    request: Request,
    status: Optional[str] = None,
    always_active: Optional[str] = None,
    search: Optional[str] = None,
    sort_field: str = 'name',
    sort_ascending: bool = True,
    limit: Optional[int] = None,
    offset: int = 0,
    current_user: Dict = Depends(get_current_user)
):
    """Get YouTube channel monitors with filtering, searching, sorting, and pagination."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    result = monitor.get_channels_filtered(
        status_filter=status,
        always_active_filter=always_active,
        search=search,
        sort_field=sort_field,
        sort_ascending=sort_ascending,
        limit=limit,
        offset=offset
    )

    return {
        "success": True,
        "channels": result['channels'],
        "total": result['total']
    }


@router.get("/platforms/youtube-monitors/active")
@limiter.limit("100/minute")
@handle_exceptions
async def get_active_youtube_channels(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get active YouTube channel monitors (deprecated - use /channels with status=active)."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    channels = monitor.get_active_channels()

    return {
        "success": True,
        "channels": channels,
        "count": len(channels)
    }


@router.get("/platforms/youtube-monitors/paused")
@limiter.limit("100/minute")
@handle_exceptions
async def get_paused_youtube_channels(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get paused YouTube channel monitors (deprecated - use /channels with status=paused_all)."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    channels = monitor.get_paused_channels()

    return {
        "success": True,
        "channels": channels,
        "count": len(channels)
    }


@router.get("/platforms/youtube-monitors/statistics")
@limiter.limit("300/minute")
@handle_exceptions
async def get_youtube_monitor_statistics(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get YouTube monitor statistics."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    stats = monitor.get_statistics()

    return {
        "success": True,
        "statistics": stats
    }


@router.post("/platforms/youtube-monitors/channels/{channel_id}/pause")
@limiter.limit("30/minute")
@handle_exceptions
async def pause_youtube_channel(
    request: Request,
    channel_id: int,
    reason: Optional[str] = None,
    current_user: Dict = Depends(get_current_user)
):
    """Manually pause a YouTube channel."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    existing = monitor.get_channel(channel_id)
    if not existing:
        raise HTTPException(status_code=404, detail="Channel not found")

    success = monitor.pause_channel(channel_id, reason=reason, auto=False)

    return {
        "success": success,
        "message": f"Channel '{existing['channel_name']}' paused"
    }


@router.post("/platforms/youtube-monitors/channels/{channel_id}/resume")
@limiter.limit("30/minute")
@handle_exceptions
async def resume_youtube_channel(
    request: Request,
    channel_id: int,
    current_user: Dict = Depends(get_current_user)
):
    """Resume a paused YouTube channel."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    existing = monitor.get_channel(channel_id)
    if not existing:
        raise HTTPException(status_code=404, detail="Channel not found")

    success = monitor.resume_channel(channel_id)

    return {
        "success": success,
        "message": f"Channel '{existing['channel_name']}' resumed"
    }


@router.post("/platforms/youtube-monitors/channels/{channel_id}/toggle-always-active")
@limiter.limit("30/minute")
@handle_exceptions
async def toggle_always_active(
    request: Request,
    channel_id: int,
    value: bool,
    current_user: Dict = Depends(get_current_user)
):
    """Toggle always_active flag for a channel."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    existing = monitor.get_channel(channel_id)
    if not existing:
        raise HTTPException(status_code=404, detail="Channel not found")

    success = monitor.toggle_always_active(channel_id, value)

    return {
        "success": success,
        "message": f"Always active {'enabled' if value else 'disabled'} for '{existing['channel_name']}'"
    }


@router.post("/platforms/youtube-monitors/check-paused")
@limiter.limit("5/minute")
@handle_exceptions
async def check_paused_channels_now(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Check paused channels for new activity."""
    from modules.youtube_channel_monitor import YouTubeChannelMonitor
    from ..core.config import Settings

    settings = Settings()
    monitor = YouTubeChannelMonitor(str(settings.DB_PATH))

    resumed = monitor.check_paused_channels_sync()

    return {
        "success": True,
        "resumed_count": resumed,
        "message": f"{resumed} channels auto-resumed" if resumed > 0 else "No channels resumed"
    }
