"""
Data Synchronization API Routes
OrbiQuant IA Trading Platform - Data Service

Endpoints for managing data synchronization with Massive.com/Polygon.io
"""

from datetime import datetime
from typing import Optional, List, Dict, Any
from fastapi import APIRouter, Depends, HTTPException, Query, status, BackgroundTasks
from pydantic import BaseModel, Field

import asyncpg

from providers.polygon_client import AssetType, Timeframe
from services.sync_service import DataSyncService, SyncStatus
from .dependencies import get_db_pool, get_polygon_client


router = APIRouter(prefix="/api/sync", tags=["Data Sync"])


# =============================================================================
# Request/Response Models
# =============================================================================

class SyncSymbolRequest(BaseModel):
    """Request to sync a specific symbol."""
    asset_type: AssetType = Field(AssetType.FOREX, description="Asset type")
    timeframe: Timeframe = Field(Timeframe.MINUTE_5, description="Timeframe to sync")
    backfill_days: int = Field(30, ge=1, le=365, description="Days to backfill")


class SyncSymbolResponse(BaseModel):
    """Response from sync operation."""
    status: str
    symbol: str
    timeframe: str
    rows_inserted: int
    start_date: Optional[str] = None
    end_date: Optional[str] = None
    error: Optional[str] = None


class SyncStatusResponse(BaseModel):
    """Sync status for a ticker."""
    symbol: str
    asset_type: str
    timeframe: Optional[str] = None
    last_sync: Optional[str] = None
    rows_synced: Optional[int] = None
    status: Optional[str] = None
    error: Optional[str] = None
    updated_at: Optional[str] = None


class SyncAllResponse(BaseModel):
    """Response from syncing all tickers."""
    total_tickers: int
    successful: int
    failed: int
    total_rows_inserted: int
    message: str


class SymbolInfo(BaseModel):
    """Information about a supported symbol."""
    symbol: str
    polygon_symbol: str
    mt4_symbol: Optional[str] = None
    asset_type: str
    pip_value: Optional[float] = None
    supported: bool = True


class SymbolsListResponse(BaseModel):
    """List of supported symbols."""
    symbols: List[SymbolInfo]
    total: int
    asset_types: List[str]


# =============================================================================
# Dependency Functions
# =============================================================================

async def get_sync_service(
    db_pool: asyncpg.Pool = Depends(get_db_pool),
    polygon_client = Depends(get_polygon_client)
) -> DataSyncService:
    """Get DataSyncService instance."""
    return DataSyncService(
        polygon_client=polygon_client,
        db_pool=db_pool,
        batch_size=10000
    )


# =============================================================================
# Symbols Endpoints
# =============================================================================

@router.get("/symbols", response_model=SymbolsListResponse)
async def list_supported_symbols(
    asset_type: Optional[AssetType] = Query(None, description="Filter by asset type"),
    sync_service: DataSyncService = Depends(get_sync_service)
):
    """
    Get list of symbols supported by Massive.com/Polygon.io.

    Returns all symbols configured in the system with their mappings.
    Can be filtered by asset type (forex, crypto, index, stock).
    """
    symbols = await sync_service.get_supported_symbols(asset_type=asset_type)

    # Get unique asset types
    asset_types = list(set(s["asset_type"] for s in symbols))

    return SymbolsListResponse(
        symbols=[SymbolInfo(**s) for s in symbols],
        total=len(symbols),
        asset_types=sorted(asset_types)
    )


@router.get("/symbols/{symbol}")
async def get_symbol_info(
    symbol: str,
    sync_service: DataSyncService = Depends(get_sync_service)
):
    """
    Get detailed information about a specific symbol.

    Includes sync status and configuration.
    """
    # Get symbol from supported list
    symbols = await sync_service.get_supported_symbols()
    symbol_info = next((s for s in symbols if s["symbol"].upper() == symbol.upper()), None)

    if not symbol_info:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Symbol {symbol} not supported"
        )

    # Get sync status
    sync_status = await sync_service.get_sync_status(symbol=symbol)

    return {
        **symbol_info,
        "sync_status": sync_status
    }


# =============================================================================
# Sync Control Endpoints
# =============================================================================

@router.post("/sync/{symbol}", response_model=SyncSymbolResponse)
async def sync_symbol(
    symbol: str,
    request: SyncSymbolRequest,
    background_tasks: BackgroundTasks,
    sync_service: DataSyncService = Depends(get_sync_service)
):
    """
    Trigger data synchronization for a specific symbol.

    This will fetch historical data from Massive.com/Polygon.io and store it
    in the database. The operation runs in the background and returns immediately.

    Parameters:
    - **symbol**: Ticker symbol (e.g., 'EURUSD', 'BTCUSD')
    - **asset_type**: Type of asset (forex, crypto, index, stock)
    - **timeframe**: Data timeframe (1m, 5m, 15m, 1h, 4h, 1d)
    - **backfill_days**: Number of days to backfill (1-365)
    """
    # Validate symbol is supported
    symbols = await sync_service.get_supported_symbols()
    if not any(s["symbol"].upper() == symbol.upper() for s in symbols):
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Symbol {symbol} not supported. Use /api/sync/symbols to see available symbols."
        )

    # Start sync in background
    result = await sync_service.sync_ticker_data(
        symbol=symbol.upper(),
        asset_type=request.asset_type,
        timeframe=request.timeframe,
        backfill_days=request.backfill_days
    )

    return SyncSymbolResponse(**result)


@router.post("/sync-all", response_model=SyncAllResponse)
async def sync_all_symbols(
    background_tasks: BackgroundTasks,
    timeframe: Timeframe = Query(Timeframe.MINUTE_5, description="Timeframe to sync"),
    backfill_days: int = Query(1, ge=1, le=30, description="Days to backfill"),
    sync_service: DataSyncService = Depends(get_sync_service)
):
    """
    Trigger synchronization for all active tickers.

    This is a heavy operation and may take a while depending on the number
    of active tickers and the API rate limits.

    Only use this for initial setup or manual full sync.
    """
    # Run sync in background
    def run_sync():
        import asyncio
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        result = loop.run_until_complete(
            sync_service.sync_all_active_tickers(
                timeframe=timeframe,
                backfill_days=backfill_days
            )
        )
        loop.close()
        return result

    background_tasks.add_task(run_sync)

    return SyncAllResponse(
        total_tickers=0,
        successful=0,
        failed=0,
        total_rows_inserted=0,
        message="Sync started in background. Check /api/sync/status for progress."
    )


# =============================================================================
# Status Endpoints
# =============================================================================

@router.get("/status", response_model=List[SyncStatusResponse])
async def get_sync_status(
    symbol: Optional[str] = Query(None, description="Filter by symbol"),
    sync_service: DataSyncService = Depends(get_sync_service)
):
    """
    Get synchronization status for all tickers or a specific symbol.

    Shows:
    - Last sync timestamp
    - Number of rows synced
    - Sync status (success, failed, in_progress)
    - Error messages if any
    """
    status_list = await sync_service.get_sync_status(symbol=symbol)

    return [SyncStatusResponse(**s) for s in status_list]


@router.get("/status/{symbol}", response_model=List[SyncStatusResponse])
async def get_symbol_sync_status(
    symbol: str,
    sync_service: DataSyncService = Depends(get_sync_service)
):
    """
    Get detailed sync status for a specific symbol across all timeframes.
    """
    status_list = await sync_service.get_sync_status(symbol=symbol)

    if not status_list:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No sync status found for symbol {symbol}"
        )

    return [SyncStatusResponse(**s) for s in status_list]


# =============================================================================
# Health Check
# =============================================================================

@router.get("/health")
async def sync_health_check(
    polygon_client = Depends(get_polygon_client),
    db_pool: asyncpg.Pool = Depends(get_db_pool)
):
    """
    Check health of sync service and data providers.

    Verifies:
    - Database connectivity
    - Polygon/Massive API accessibility
    - Rate limit status
    """
    health = {
        "status": "healthy",
        "timestamp": datetime.utcnow().isoformat(),
        "providers": {}
    }

    # Check database
    try:
        async with db_pool.acquire() as conn:
            await conn.fetchval("SELECT 1")
        health["providers"]["database"] = {
            "status": "connected",
            "type": "PostgreSQL"
        }
    except Exception as e:
        health["status"] = "unhealthy"
        health["providers"]["database"] = {
            "status": "error",
            "error": str(e)
        }

    # Check Polygon API (basic connectivity)
    try:
        health["providers"]["polygon"] = {
            "status": "configured",
            "base_url": polygon_client.base_url,
            "rate_limit": f"{polygon_client.rate_limit} req/min"
        }
    except Exception as e:
        health["status"] = "degraded"
        health["providers"]["polygon"] = {
            "status": "error",
            "error": str(e)
        }

    return health
