"""
Stats Router

Handles statistics, monitoring, settings, and integrations:
- Dashboard statistics
- Downloader monitoring
- Settings management
- Immich integration
"""

import json
import sqlite3
import time
from typing import Dict, Optional

import requests
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, require_admin, get_app_state
from ..core.exceptions import handle_exceptions, NotFoundError, ValidationError
from modules.universal_logger import get_logger

logger = get_logger('API')

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


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

class SettingUpdate(BaseModel):
    value: dict | list | str | int | float | bool
    category: Optional[str] = None
    description: Optional[str] = None


# ============================================================================
# DASHBOARD STATISTICS
# ============================================================================

@router.get("/stats/dashboard")
@limiter.limit("60/minute")
@handle_exceptions
async def get_dashboard_stats(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get comprehensive dashboard statistics."""
    app_state = get_app_state()

    with app_state.db.get_connection() as conn:
        cursor = conn.cursor()

        # Get download counts per platform (combine downloads and video_downloads)
        cursor.execute("""
            SELECT platform, SUM(cnt) as count FROM (
                SELECT platform, COUNT(*) as cnt FROM downloads GROUP BY platform
                UNION ALL
                SELECT platform, COUNT(*) as cnt FROM video_downloads GROUP BY platform
            ) GROUP BY platform
        """)

        platform_data = {}
        for row in cursor.fetchall():
            platform = row[0]
            if platform not in platform_data:
                platform_data[platform] = {
                    'count': 0,
                    'size_bytes': 0
                }
            platform_data[platform]['count'] += row[1]

        # Calculate storage sizes from file_inventory (final + review)
        cursor.execute("""
            SELECT platform, COALESCE(SUM(file_size), 0) as total_size
            FROM file_inventory
            WHERE location IN ('final', 'review')
            GROUP BY platform
        """)

        for row in cursor.fetchall():
            platform = row[0]
            if platform not in platform_data:
                platform_data[platform] = {'count': 0, 'size_bytes': 0}
            platform_data[platform]['size_bytes'] += row[1]

        # Only show platforms with actual files
        storage_by_platform = []
        for platform in sorted(platform_data.keys(), key=lambda p: platform_data[p]['size_bytes'], reverse=True):
            if platform_data[platform]['size_bytes'] > 0:
                storage_by_platform.append({
                    'platform': platform,
                    'count': platform_data[platform]['count'],
                    'size_bytes': platform_data[platform]['size_bytes'],
                    'size_mb': round(platform_data[platform]['size_bytes'] / 1024 / 1024, 2)
                })

        # Downloads per day (last 30 days) - combine downloads and video_downloads
        cursor.execute("""
            SELECT date, SUM(count) as count FROM (
                SELECT DATE(download_date) as date, COUNT(*) as count
                FROM downloads
                WHERE download_date >= DATE('now', '-30 days')
                GROUP BY DATE(download_date)
                UNION ALL
                SELECT DATE(download_date) as date, COUNT(*) as count
                FROM video_downloads
                WHERE download_date >= DATE('now', '-30 days')
                GROUP BY DATE(download_date)
            ) GROUP BY date ORDER BY date
        """)
        downloads_per_day = [{'date': row[0], 'count': row[1]} for row in cursor.fetchall()]

        # Content type breakdown
        cursor.execute("""
            SELECT
                content_type,
                COUNT(*) as count
            FROM downloads
            WHERE content_type IS NOT NULL
            GROUP BY content_type
            ORDER BY count DESC
        """)
        content_types = {row[0]: row[1] for row in cursor.fetchall()}

        # Top sources
        cursor.execute("""
            SELECT
                source,
                platform,
                COUNT(*) as count
            FROM downloads
            WHERE source IS NOT NULL
            GROUP BY source, platform
            ORDER BY count DESC
            LIMIT 10
        """)
        top_sources = [{'source': row[0], 'platform': row[1], 'count': row[2]} for row in cursor.fetchall()]

        # Total statistics - use file_inventory for accurate file counts
        cursor.execute("""
            SELECT
                (SELECT COUNT(*) FROM file_inventory WHERE location IN ('final', 'review')) as total_downloads,
                (SELECT COALESCE(SUM(file_size), 0) FROM file_inventory WHERE location IN ('final', 'review')) as total_size,
                (SELECT COUNT(DISTINCT source) FROM downloads) +
                (SELECT COUNT(DISTINCT uploader) FROM video_downloads) as unique_sources,
                (SELECT COUNT(DISTINCT platform) FROM file_inventory) as platforms_used
        """)
        totals = cursor.fetchone()

        # Get recycle bin and review counts separately
        cursor.execute("SELECT COUNT(*) FROM recycle_bin")
        recycle_count = cursor.fetchone()[0] or 0

        cursor.execute("SELECT COUNT(*) FROM file_inventory WHERE location = 'review'")
        review_count = cursor.fetchone()[0] or 0

        # Growth rate - combine downloads and video_downloads
        cursor.execute("""
            SELECT
                (SELECT SUM(CASE WHEN download_date >= DATE('now', '-7 days') THEN 1 ELSE 0 END) FROM downloads) +
                (SELECT SUM(CASE WHEN download_date >= DATE('now', '-7 days') THEN 1 ELSE 0 END) FROM video_downloads) as this_week,
                (SELECT SUM(CASE WHEN download_date >= DATE('now', '-14 days') AND download_date < DATE('now', '-7 days') THEN 1 ELSE 0 END) FROM downloads) +
                (SELECT SUM(CASE WHEN download_date >= DATE('now', '-14 days') AND download_date < DATE('now', '-7 days') THEN 1 ELSE 0 END) FROM video_downloads) as last_week
        """)
        growth_row = cursor.fetchone()
        growth_rate = 0
        if growth_row and growth_row[1] > 0:
            growth_rate = round(((growth_row[0] - growth_row[1]) / growth_row[1]) * 100, 1)

        return {
            'storage_by_platform': storage_by_platform,
            'downloads_per_day': downloads_per_day,
            'content_types': content_types,
            'top_sources': top_sources,
            'totals': {
                'total_downloads': totals[0] or 0,
                'total_size_bytes': totals[1] or 0,
                'total_size_gb': round((totals[1] or 0) / 1024 / 1024 / 1024, 2),
                'unique_sources': totals[2] or 0,
                'platforms_used': totals[3] or 0,
                'recycle_bin_count': recycle_count,
                'review_count': review_count
            },
            'growth_rate': growth_rate
        }


# ============================================================================
# FLARESOLVERR HEALTH CHECK
# ============================================================================

@router.get("/health/flaresolverr")
@limiter.limit("60/minute")
@handle_exceptions
async def check_flaresolverr_health(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Check FlareSolverr health status."""
    app_state = get_app_state()

    flaresolverr_url = "http://localhost:8191/v1"

    try:
        with app_state.db.get_connection() as conn:
            cursor = conn.cursor()
            cursor.execute("SELECT value FROM settings WHERE key='flaresolverr'")
            result = cursor.fetchone()
            if result:
                flaresolverr_config = json.loads(result[0])
                if 'url' in flaresolverr_config:
                    flaresolverr_url = flaresolverr_config['url']
    except (sqlite3.Error, json.JSONDecodeError, KeyError):
        pass

    start_time = time.time()

    try:
        response = requests.post(
            flaresolverr_url,
            json={"cmd": "sessions.list"},
            timeout=5
        )
        response_time = round((time.time() - start_time) * 1000, 2)

        if response.status_code == 200:
            return {
                'status': 'healthy',
                'url': flaresolverr_url,
                'response_time_ms': response_time,
                'last_check': time.time(),
                'sessions': response.json().get('sessions', [])
            }
        else:
            return {
                'status': 'unhealthy',
                'url': flaresolverr_url,
                'response_time_ms': response_time,
                'last_check': time.time(),
                'error': f"HTTP {response.status_code}: {response.text}"
            }
    except requests.exceptions.ConnectionError:
        return {
            'status': 'offline',
            'url': flaresolverr_url,
            'last_check': time.time(),
            'error': 'Connection refused - FlareSolverr may not be running'
        }
    except requests.exceptions.Timeout:
        return {
            'status': 'timeout',
            'url': flaresolverr_url,
            'last_check': time.time(),
            'error': 'Request timed out after 5 seconds'
        }
    except Exception as e:
        return {
            'status': 'error',
            'url': flaresolverr_url,
            'last_check': time.time(),
            'error': str(e)
        }


# ============================================================================
# MONITORING ENDPOINTS
# ============================================================================

@router.get("/monitoring/status")
@limiter.limit("100/minute")
@handle_exceptions
async def get_monitoring_status(
    request: Request,
    hours: int = 24,
    current_user: Dict = Depends(get_current_user)
):
    """Get downloader monitoring status."""
    from modules.downloader_monitor import get_monitor

    app_state = get_app_state()
    monitor = get_monitor(app_state.db, app_state.settings)
    status = monitor.get_downloader_status(hours=hours)

    return {
        "success": True,
        "downloaders": status,
        "window_hours": hours
    }


@router.get("/monitoring/history")
@limiter.limit("100/minute")
@handle_exceptions
async def get_monitoring_history(
    request: Request,
    downloader: str = None,
    limit: int = 100,
    current_user: Dict = Depends(get_current_user)
):
    """Get download monitoring history."""
    app_state = get_app_state()

    with app_state.db.get_connection() as conn:
        cursor = conn.cursor()

        if downloader:
            cursor.execute("""
                SELECT
                    id, downloader, username, timestamp, success,
                    file_count, error_message, alert_sent
                FROM download_monitor
                WHERE downloader = ?
                ORDER BY timestamp DESC
                LIMIT ?
            """, (downloader, limit))
        else:
            cursor.execute("""
                SELECT
                    id, downloader, username, timestamp, success,
                    file_count, error_message, alert_sent
                FROM download_monitor
                ORDER BY timestamp DESC
                LIMIT ?
            """, (limit,))

        history = []
        for row in cursor.fetchall():
            history.append({
                'id': row['id'],
                'downloader': row['downloader'],
                'username': row['username'],
                'timestamp': row['timestamp'],
                'success': bool(row['success']),
                'file_count': row['file_count'],
                'error_message': row['error_message'],
                'alert_sent': bool(row['alert_sent'])
            })

        return {
            "success": True,
            "history": history
        }


@router.delete("/monitoring/history")
@limiter.limit("10/minute")
@handle_exceptions
async def clear_monitoring_history(
    request: Request,
    days: int = 30,
    current_user: Dict = Depends(require_admin)
):
    """Clear old monitoring logs."""
    from modules.downloader_monitor import get_monitor

    app_state = get_app_state()
    monitor = get_monitor(app_state.db, app_state.settings)
    monitor.clear_old_logs(days=days)

    return {
        "success": True,
        "message": f"Cleared logs older than {days} days"
    }


# ============================================================================
# SETTINGS ENDPOINTS
# ============================================================================

@router.get("/settings/{key}")
@limiter.limit("60/minute")
@handle_exceptions
async def get_setting(
    request: Request,
    key: str,
    current_user: Dict = Depends(get_current_user)
):
    """Get a specific setting value."""
    app_state = get_app_state()
    value = app_state.settings.get(key)
    if value is None:
        raise NotFoundError(f"Setting '{key}' not found")
    return value


@router.put("/settings/{key}")
@limiter.limit("30/minute")
@handle_exceptions
async def update_setting(
    request: Request,
    key: str,
    body: Dict,
    current_user: Dict = Depends(require_admin)
):
    """Update a specific setting value."""
    app_state = get_app_state()

    value = body.get('value')
    if value is None:
        raise ValidationError("Missing 'value' in request body")

    app_state.settings.set(
        key=key,
        value=value,
        category=body.get('category'),
        description=body.get('description'),
        updated_by=current_user.get('username', 'user')
    )

    return {
        "success": True,
        "message": f"Setting '{key}' updated successfully"
    }


# ============================================================================
# IMMICH INTEGRATION
# ============================================================================

@router.post("/immich/scan")
@limiter.limit("10/minute")
@handle_exceptions
async def trigger_immich_scan(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Trigger Immich library scan."""
    app_state = get_app_state()

    immich_config = app_state.settings.get('immich', {})

    if not immich_config.get('enabled'):
        return {
            "success": False,
            "message": "Immich integration is not enabled"
        }

    api_url = immich_config.get('api_url')
    api_key = immich_config.get('api_key')
    library_id = immich_config.get('library_id')

    if not all([api_url, api_key, library_id]):
        return {
            "success": False,
            "message": "Immich configuration incomplete (missing api_url, api_key, or library_id)"
        }

    try:
        response = requests.post(
            f"{api_url}/libraries/{library_id}/scan",
            headers={'X-API-KEY': api_key},
            timeout=10
        )

        if response.status_code in [200, 201, 204]:
            return {
                "success": True,
                "message": f"Successfully triggered Immich scan for library {library_id}"
            }
        else:
            return {
                "success": False,
                "message": f"Immich scan request failed with status {response.status_code}: {response.text}"
            }

    except requests.exceptions.RequestException as e:
        return {
            "success": False,
            "message": f"Failed to connect to Immich: {str(e)}"
        }


# ============================================================================
# ERROR MONITORING SETTINGS
# ============================================================================

class ErrorMonitoringSettings(BaseModel):
    enabled: bool = True
    push_alert_enabled: bool = True
    push_alert_delay_hours: int = 24
    dashboard_banner_enabled: bool = True
    retention_days: int = 7


@router.get("/error-monitoring/settings")
@limiter.limit("60/minute")
@handle_exceptions
async def get_error_monitoring_settings(
    request: Request,
    current_user: Dict = Depends(get_current_user)
):
    """Get error monitoring settings."""
    app_state = get_app_state()

    settings = app_state.settings.get('error_monitoring', {
        'enabled': True,
        'push_alert_enabled': True,
        'push_alert_delay_hours': 24,
        'dashboard_banner_enabled': True,
        'retention_days': 7
    })

    return settings


@router.put("/error-monitoring/settings")
@limiter.limit("30/minute")
@handle_exceptions
async def update_error_monitoring_settings(
    request: Request,
    settings: ErrorMonitoringSettings,
    current_user: Dict = Depends(get_current_user)
):
    """Update error monitoring settings."""
    app_state = get_app_state()

    app_state.settings.set(
        key='error_monitoring',
        value=settings.model_dump(),
        category='monitoring',
        description='Error monitoring and alert settings',
        updated_by=current_user.get('username', 'user')
    )

    return {
        "success": True,
        "message": "Error monitoring settings updated",
        "settings": settings.model_dump()
    }
