"""
Instagram Unified Configuration Router

Provides a single configuration interface for all Instagram scrapers.
Manages one central account list with per-account content type toggles,
scraper assignments, and auto-generates legacy per-scraper configs on save.
"""

import copy
from typing import Any, Dict, List, Optional

from fastapi import APIRouter, Depends, 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 modules.universal_logger import get_logger

logger = get_logger('API')

router = APIRouter(prefix="/api/instagram-unified", tags=["Instagram Unified"])
limiter = Limiter(key_func=get_remote_address)

# Scraper capability matrix
SCRAPER_CAPABILITIES = {
    'fastdl': {'posts': True, 'stories': True, 'reels': True, 'tagged': False},
    'imginn_api': {'posts': True, 'stories': True, 'reels': False, 'tagged': True},
    'imginn': {'posts': True, 'stories': True, 'reels': False, 'tagged': True},
    'toolzu': {'posts': True, 'stories': True, 'reels': False, 'tagged': False},
    'instagram_client': {'posts': True, 'stories': True, 'reels': True, 'tagged': True},
    'instagram': {'posts': True, 'stories': True, 'reels': False, 'tagged': True},
}

SCRAPER_LABELS = {
    'fastdl': 'FastDL',
    'imginn_api': 'ImgInn API',
    'imginn': 'ImgInn',
    'toolzu': 'Toolzu',
    'instagram_client': 'Instagram Client',
    'instagram': 'InstaLoader',
}

CONTENT_TYPES = ['posts', 'stories', 'reels', 'tagged']

LEGACY_SCRAPER_KEYS = ['fastdl', 'imginn_api', 'imginn', 'toolzu', 'instagram_client', 'instagram']

# Default destination paths
DEFAULT_PATHS = {
    'posts': '/opt/immich/md/social media/instagram/posts',
    'stories': '/opt/immich/md/social media/instagram/stories',
    'reels': '/opt/immich/md/social media/instagram/reels',
    'tagged': '/opt/immich/md/social media/instagram/tagged',
}


class UnifiedConfigUpdate(BaseModel):
    config: Dict[str, Any]


# ============================================================================
# MIGRATION LOGIC
# ============================================================================

def _migrate_from_legacy(app_state) -> Dict[str, Any]:
    """
    Build a unified config from existing per-scraper configs.
    Called on first load when no instagram_unified key exists.
    """
    settings = app_state.settings

    # Load all legacy configs
    legacy = {}
    for key in LEGACY_SCRAPER_KEYS:
        legacy[key] = settings.get(key) or {}

    # Determine scraper assignments from currently enabled configs
    # Only assign a scraper if it actually supports the content type per capability matrix
    scraper_assignment = {}
    for ct in CONTENT_TYPES:
        assigned = None
        for scraper_key in LEGACY_SCRAPER_KEYS:
            cfg = legacy[scraper_key]
            if (cfg.get('enabled') and cfg.get(ct, {}).get('enabled')
                    and SCRAPER_CAPABILITIES.get(scraper_key, {}).get(ct)):
                assigned = scraper_key
                break
        # Fallback defaults if nothing is enabled — pick first capable scraper
        if not assigned:
            if ct in ('posts', 'tagged'):
                assigned = 'imginn_api'
            elif ct in ('stories', 'reels'):
                assigned = 'fastdl'
        scraper_assignment[ct] = assigned

    # Collect all unique usernames from all scrapers
    all_usernames = set()
    scraper_usernames = {}  # track which usernames belong to which scraper

    for scraper_key in LEGACY_SCRAPER_KEYS:
        cfg = legacy[scraper_key]
        usernames = []

        if scraper_key == 'instagram':
            # InstaLoader uses accounts list format
            for acc in cfg.get('accounts', []):
                u = acc.get('username')
                if u:
                    usernames.append(u)
        else:
            usernames = cfg.get('usernames', [])

        # Also include phrase_search usernames
        ps_usernames = cfg.get('phrase_search', {}).get('usernames', [])
        combined = set(usernames) | set(ps_usernames)
        scraper_usernames[scraper_key] = combined
        all_usernames |= combined

    # Build per-account content type flags
    # An account gets a content type enabled if:
    # - The scraper assigned to that content type has this username in its list
    accounts = []
    for username in sorted(all_usernames):
        account = {'username': username}
        for ct in CONTENT_TYPES:
            assigned_scraper = scraper_assignment[ct]
            # Enable if this user is in the assigned scraper's list
            account[ct] = username in scraper_usernames.get(assigned_scraper, set())
        accounts.append(account)

    # Import content type settings from the first enabled scraper that has them
    content_types = {}
    for ct in CONTENT_TYPES:
        ct_config = {'enabled': False, 'days_back': 7, 'destination_path': DEFAULT_PATHS[ct]}
        assigned = scraper_assignment[ct]
        cfg = legacy.get(assigned, {})
        ct_sub = cfg.get(ct, {})
        if ct_sub.get('enabled'):
            ct_config['enabled'] = True
        if ct_sub.get('days_back'):
            ct_config['days_back'] = ct_sub['days_back']
        if ct_sub.get('destination_path'):
            ct_config['destination_path'] = ct_sub['destination_path']
        content_types[ct] = ct_config

    # Import phrase search from first scraper that has it enabled
    phrase_search = {
        'enabled': False,
        'download_all': True,
        'phrases': [],
        'case_sensitive': False,
        'match_all': False,
    }
    for scraper_key in LEGACY_SCRAPER_KEYS:
        ps = legacy[scraper_key].get('phrase_search', {})
        if ps.get('enabled') or ps.get('phrases'):
            phrase_search['enabled'] = ps.get('enabled', False)
            phrase_search['download_all'] = ps.get('download_all', True)
            phrase_search['phrases'] = ps.get('phrases', [])
            phrase_search['case_sensitive'] = ps.get('case_sensitive', False)
            phrase_search['match_all'] = ps.get('match_all', False)
            break

    # Import scraper-specific settings (auth, cookies, etc.)
    scraper_settings = {
        'fastdl': {},
        'imginn_api': {},
        'imginn': {'cookie_file': legacy['imginn'].get('cookie_file', '')},
        'toolzu': {
            'email': legacy['toolzu'].get('email', ''),
            'password': legacy['toolzu'].get('password', ''),
            'cookie_file': legacy['toolzu'].get('cookie_file', ''),
        },
        'instagram_client': {},
        'instagram': {
            'username': legacy['instagram'].get('username', ''),
            'password': legacy['instagram'].get('password', ''),
            'totp_secret': legacy['instagram'].get('totp_secret', ''),
            'session_file': legacy['instagram'].get('session_file', ''),
        },
    }

    # Get global settings from the primary enabled scraper
    check_interval = 8
    run_at_start = False
    user_delay = 20
    for scraper_key in ['fastdl', 'imginn_api']:
        cfg = legacy[scraper_key]
        if cfg.get('enabled'):
            check_interval = cfg.get('check_interval_hours', 8)
            run_at_start = cfg.get('run_at_start', False)
            user_delay = cfg.get('user_delay_seconds', 20)
            break

    return {
        'enabled': True,
        'check_interval_hours': check_interval,
        'run_at_start': run_at_start,
        'user_delay_seconds': user_delay,
        'scraper_assignment': scraper_assignment,
        'content_types': content_types,
        'accounts': accounts,
        'phrase_search': phrase_search,
        'scraper_settings': scraper_settings,
    }


# ============================================================================
# LEGACY CONFIG GENERATION
# ============================================================================

def _generate_legacy_configs(unified: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
    """
    From the unified config, generate 6 legacy per-scraper configs
    that the existing scraper modules can consume.
    """
    scraper_assignment = unified.get('scraper_assignment', {})
    content_types = unified.get('content_types', {})
    accounts = unified.get('accounts', [])
    phrase_search = unified.get('phrase_search', {})
    scraper_settings = unified.get('scraper_settings', {})

    # For each scraper, determine which content types it's assigned to
    scraper_content_types = {key: [] for key in LEGACY_SCRAPER_KEYS}
    for ct, scraper_key in scraper_assignment.items():
        if scraper_key in scraper_content_types:
            scraper_content_types[scraper_key].append(ct)

    # For each scraper, collect usernames that have any of its assigned content types enabled
    scraper_usernames = {key: set() for key in LEGACY_SCRAPER_KEYS}
    for account in accounts:
        username = account.get('username', '')
        if not username:
            continue
        for ct, scraper_key in scraper_assignment.items():
            if account.get(ct, False):
                scraper_usernames[scraper_key].add(username)

    # Build legacy configs
    result = {}
    for scraper_key in LEGACY_SCRAPER_KEYS:
        assigned_cts = scraper_content_types[scraper_key]
        usernames = sorted(scraper_usernames[scraper_key])
        is_enabled = unified.get('enabled', False) and len(assigned_cts) > 0 and len(usernames) > 0
        extra_settings = scraper_settings.get(scraper_key, {})

        cfg = {
            'enabled': is_enabled,
            'check_interval_hours': unified.get('check_interval_hours', 8),
            'run_at_start': unified.get('run_at_start', False),
        }

        # Add user_delay_seconds for scrapers that support it
        if scraper_key in ('imginn_api', 'instagram_client'):
            cfg['user_delay_seconds'] = unified.get('user_delay_seconds', 20)

        # Add scraper-specific settings
        if scraper_key == 'fastdl':
            cfg['high_res'] = True  # Always use high resolution
        elif scraper_key == 'imginn':
            cfg['cookie_file'] = extra_settings.get('cookie_file', '')
        elif scraper_key == 'toolzu':
            cfg['email'] = extra_settings.get('email', '')
            cfg['password'] = extra_settings.get('password', '')
            cfg['cookie_file'] = extra_settings.get('cookie_file', '')

        # InstaLoader uses accounts format + auth fields at top level
        if scraper_key == 'instagram':
            ig_settings = extra_settings
            cfg['method'] = 'instaloader'
            cfg['username'] = ig_settings.get('username', '')
            cfg['password'] = ig_settings.get('password', '')
            cfg['totp_secret'] = ig_settings.get('totp_secret', '')
            cfg['session_file'] = ig_settings.get('session_file', '')
            cfg['accounts'] = [
                {'username': u, 'check_interval_hours': unified.get('check_interval_hours', 8), 'run_at_start': False}
                for u in usernames
            ]
        else:
            cfg['usernames'] = usernames

        # Content type sub-configs
        for ct in CONTENT_TYPES:
            ct_global = content_types.get(ct, {})
            if ct in assigned_cts:
                cfg[ct] = {
                    'enabled': ct_global.get('enabled', False),
                    'days_back': ct_global.get('days_back', 7),
                    'destination_path': ct_global.get('destination_path', DEFAULT_PATHS.get(ct, '')),
                }
                # Add temp_dir based on scraper key
                cfg[ct]['temp_dir'] = f'temp/{scraper_key}/{ct}'
            else:
                cfg[ct] = {'enabled': False}

        # Phrase search goes on the scraper assigned to posts
        posts_scraper = scraper_assignment.get('posts')
        if scraper_key == posts_scraper and phrase_search.get('enabled'):
            # Collect all usernames that have posts enabled for the phrase search usernames list
            ps_usernames = sorted(scraper_usernames.get(scraper_key, set()))
            cfg['phrase_search'] = {
                'enabled': phrase_search.get('enabled', False),
                'download_all': phrase_search.get('download_all', True),
                'usernames': ps_usernames,
                'phrases': phrase_search.get('phrases', []),
                'case_sensitive': phrase_search.get('case_sensitive', False),
                'match_all': phrase_search.get('match_all', False),
            }
        else:
            cfg['phrase_search'] = {
                'enabled': False,
                'usernames': [],
                'phrases': [],
                'case_sensitive': False,
                'match_all': False,
            }

        result[scraper_key] = cfg

    return result


# ============================================================================
# ENDPOINTS
# ============================================================================

@router.get("/config")
@handle_exceptions
async def get_config(request: Request, user=Depends(get_current_user)):
    """
    Load unified config. Auto-migrates from legacy configs on first load.
    Returns config (or generated migration preview), hidden_modules, and scraper capabilities.
    """
    app_state = get_app_state()
    existing = app_state.settings.get('instagram_unified')
    hidden_modules = app_state.settings.get('hidden_modules') or []

    if existing:
        return {
            'config': existing,
            'migrated': False,
            'hidden_modules': hidden_modules,
            'scraper_capabilities': SCRAPER_CAPABILITIES,
            'scraper_labels': SCRAPER_LABELS,
        }

    # No unified config yet — generate migration preview (not auto-saved)
    migrated_config = _migrate_from_legacy(app_state)
    return {
        'config': migrated_config,
        'migrated': True,
        'hidden_modules': hidden_modules,
        'scraper_capabilities': SCRAPER_CAPABILITIES,
        'scraper_labels': SCRAPER_LABELS,
    }


@router.put("/config")
@handle_exceptions
async def update_config(request: Request, body: UnifiedConfigUpdate, user=Depends(get_current_user)):
    """
    Save unified config + generate 6 legacy configs.
    """
    app_state = get_app_state()
    config = body.config

    # Validate scraper assignments against capability matrix
    scraper_assignment = config.get('scraper_assignment', {})
    for ct, scraper_key in scraper_assignment.items():
        if ct not in CONTENT_TYPES:
            raise ValidationError(f"Unknown content type: {ct}")
        if scraper_key not in SCRAPER_CAPABILITIES:
            raise ValidationError(f"Unknown scraper: {scraper_key}")
        if not SCRAPER_CAPABILITIES[scraper_key].get(ct):
            raise ValidationError(
                f"Scraper {SCRAPER_LABELS.get(scraper_key, scraper_key)} does not support {ct}"
            )

    # Save unified config
    app_state.settings.set(
        key='instagram_unified',
        value=config,
        category='scrapers',
        description='Unified Instagram configuration',
        updated_by='api'
    )

    # Generate and save 6 legacy configs
    legacy_configs = _generate_legacy_configs(config)
    for scraper_key, legacy_cfg in legacy_configs.items():
        app_state.settings.set(
            key=scraper_key,
            value=legacy_cfg,
            category='scrapers',
            description=f'{SCRAPER_LABELS.get(scraper_key, scraper_key)} configuration (auto-generated)',
            updated_by='api'
        )

    # Refresh in-memory config
    if hasattr(app_state, 'config') and app_state.config is not None:
        app_state.config['instagram_unified'] = config
        for scraper_key, legacy_cfg in legacy_configs.items():
            app_state.config[scraper_key] = legacy_cfg

    # Broadcast config update via WebSocket
    try:
        if hasattr(app_state, 'websocket_manager') and app_state.websocket_manager:
            import asyncio
            asyncio.create_task(app_state.websocket_manager.broadcast({
                'type': 'config_updated',
                'data': {'source': 'instagram_unified'}
            }))
    except Exception as e:
        logger.warning(f"Failed to broadcast config update: {e}", module="InstagramUnified")

    return {
        'success': True,
        'message': 'Instagram configuration saved',
        'legacy_configs_updated': list(legacy_configs.keys()),
    }


@router.get("/capabilities")
@handle_exceptions
async def get_capabilities(request: Request, user=Depends(get_current_user)):
    """Return scraper capability matrix and hidden modules."""
    app_state = get_app_state()
    hidden_modules = app_state.settings.get('hidden_modules') or []

    return {
        'scraper_capabilities': SCRAPER_CAPABILITIES,
        'scraper_labels': SCRAPER_LABELS,
        'hidden_modules': hidden_modules,
        'content_types': CONTENT_TYPES,
    }
