"""
Service Proxy - Routes requests to microservices
Fetches client-specific configuration and passes to services
"""
from fastapi import APIRouter, Depends, HTTPException, status, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
import httpx
import structlog
import json

from app.database import get_db
from app.auth.dependencies import get_current_user, require_permissions
from app.models.user import User
from app.models.usage import UsageLog
from app.models.service_config import ServiceConfig, ServiceCredential, ServiceType
from app.config import settings

logger = structlog.get_logger()
router = APIRouter()

# Service URLs mapping
SERVICE_URLS = {
    "chatbot": settings.CHATBOT_SERVICE_URL,
    "document": settings.DOCUMENT_SERVICE_URL,
    "analytics": settings.ANALYTICS_SERVICE_URL,
    "vision": settings.VISION_SERVICE_URL
}

# Map service name to ServiceType enum
SERVICE_TYPE_MAP = {
    "chatbot": ServiceType.CHATBOT,
    "document": ServiceType.DOCUMENT_INTELLIGENCE,
    "analytics": ServiceType.ANALYTICS,
    "vision": ServiceType.VISION
}


async def get_client_service_config(
    client_id: str,
    service_name: str,
    db: AsyncSession
) -> dict:
    """Get client-specific configuration for a service"""
    service_type = SERVICE_TYPE_MAP.get(service_name)
    if not service_type or not client_id:
        return {}

    query = select(ServiceConfig).where(
        ServiceConfig.client_id == client_id,
        ServiceConfig.service_type == service_type
    )
    result = await db.execute(query)
    config = result.scalar_one_or_none()

    if not config:
        return {}

    return {
        "ai_provider": config.ai_provider,
        "ai_model": config.ai_model,
        "settings": config.settings or {},
        "branding": config.branding or {},
        "rate_limit": config.rate_limit_per_minute
    }


async def get_client_credentials(
    client_id: str,
    service_name: str,
    db: AsyncSession
) -> dict:
    """Get client-specific credentials for a service"""
    service_type = SERVICE_TYPE_MAP.get(service_name)
    if not service_type or not client_id:
        return {}

    query = select(ServiceCredential).where(
        ServiceCredential.client_id == client_id,
        ServiceCredential.service_type == service_type,
        ServiceCredential.is_active == True
    )
    result = await db.execute(query)
    credentials = result.scalars().all()

    creds_dict = {}
    for cred in credentials:
        creds_dict[cred.provider] = cred.credentials

    return creds_dict


async def proxy_request(
    service: str,
    path: str,
    method: str,
    request: Request,
    current_user: User,
    db: AsyncSession,
    body: dict = None
) -> Response:
    """
    Proxy a request to a microservice with client configuration
    """
    service_url = SERVICE_URLS.get(service)
    if not service_url:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Unknown service: {service}"
        )

    # Build target URL
    target_url = f"{service_url}{path}"

    # Get client-specific configuration
    client_config = await get_client_service_config(
        current_user.client_id, service, db
    )
    client_credentials = await get_client_credentials(
        current_user.client_id, service, db
    )

    # Forward headers with client config
    headers = {
        "Content-Type": "application/json",
        "X-User-ID": str(current_user.id),
        "X-Client-ID": str(current_user.client_id) if current_user.client_id else "",
        "X-User-Email": current_user.email,
        "X-User-Role": current_user.role.value,
        "X-Request-ID": getattr(request.state, 'request_id', ''),
        # Pass client configuration as headers
        "X-Client-Config": json.dumps(client_config) if client_config else "{}",
        "X-AI-Provider": client_config.get("ai_provider", "openai"),
        "X-AI-Model": client_config.get("ai_model", "gpt-4"),
    }

    # Pass credentials securely (in production, use encrypted headers or internal network)
    if client_credentials:
        headers["X-Client-Credentials"] = json.dumps(client_credentials)

    try:
        async with httpx.AsyncClient(timeout=60.0) as client:
            if method == "GET":
                response = await client.get(target_url, headers=headers, params=dict(request.query_params))
            elif method == "POST":
                response = await client.post(target_url, headers=headers, json=body)
            elif method == "PUT":
                response = await client.put(target_url, headers=headers, json=body)
            elif method == "PATCH":
                response = await client.patch(target_url, headers=headers, json=body)
            elif method == "DELETE":
                response = await client.delete(target_url, headers=headers)
            else:
                raise HTTPException(
                    status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
                    detail=f"Method {method} not allowed"
                )

        # Log usage
        usage_log = UsageLog(
            client_id=current_user.client_id,
            service_type=service,
            resource_type="api_call",
            quantity=1,
            metadata={
                "path": path,
                "method": method,
                "status_code": response.status_code,
                "ai_provider": client_config.get("ai_provider"),
                "ai_model": client_config.get("ai_model")
            },
            request_id=getattr(request.state, 'request_id', None),
            ip_address=request.client.host if request.client else None
        )
        db.add(usage_log)
        await db.commit()

        return Response(
            content=response.content,
            status_code=response.status_code,
            headers=dict(response.headers),
            media_type="application/json"
        )

    except httpx.ConnectError:
        logger.error(f"Failed to connect to {service} service", url=target_url)
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail=f"{service.title()} service is unavailable"
        )
    except httpx.TimeoutException:
        logger.error(f"Timeout connecting to {service} service", url=target_url)
        raise HTTPException(
            status_code=status.HTTP_504_GATEWAY_TIMEOUT,
            detail=f"{service.title()} service request timed out"
        )


# ============ CHATBOT SERVICE ROUTES ============

@router.get("/chatbot/{path:path}")
async def chatbot_get(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("chatbot:read")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy GET requests to chatbot service"""
    return await proxy_request("chatbot", f"/{path}", "GET", request, current_user, db)


@router.post("/chatbot/{path:path}")
async def chatbot_post(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("chatbot:write")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy POST requests to chatbot service"""
    body = await request.json() if request.headers.get("content-type") == "application/json" else {}
    return await proxy_request("chatbot", f"/{path}", "POST", request, current_user, db, body)


@router.put("/chatbot/{path:path}")
async def chatbot_put(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("chatbot:write")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy PUT requests to chatbot service"""
    body = await request.json() if request.headers.get("content-type") == "application/json" else {}
    return await proxy_request("chatbot", f"/{path}", "PUT", request, current_user, db, body)


@router.delete("/chatbot/{path:path}")
async def chatbot_delete(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("chatbot:delete")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy DELETE requests to chatbot service"""
    return await proxy_request("chatbot", f"/{path}", "DELETE", request, current_user, db)


# ============ DOCUMENT SERVICE ROUTES ============

@router.get("/document/{path:path}")
async def document_get(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("document:read")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy GET requests to document service"""
    return await proxy_request("document", f"/{path}", "GET", request, current_user, db)


@router.post("/document/{path:path}")
async def document_post(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("document:write")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy POST requests to document service"""
    body = await request.json() if request.headers.get("content-type") == "application/json" else {}
    return await proxy_request("document", f"/{path}", "POST", request, current_user, db, body)


@router.put("/document/{path:path}")
async def document_put(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("document:write")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy PUT requests to document service"""
    body = await request.json() if request.headers.get("content-type") == "application/json" else {}
    return await proxy_request("document", f"/{path}", "PUT", request, current_user, db, body)


@router.delete("/document/{path:path}")
async def document_delete(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("document:delete")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy DELETE requests to document service"""
    return await proxy_request("document", f"/{path}", "DELETE", request, current_user, db)


# ============ ANALYTICS SERVICE ROUTES ============

@router.get("/analytics/{path:path}")
async def analytics_get(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("analytics:read")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy GET requests to analytics service"""
    return await proxy_request("analytics", f"/{path}", "GET", request, current_user, db)


@router.post("/analytics/{path:path}")
async def analytics_post(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("analytics:write")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy POST requests to analytics service"""
    body = await request.json() if request.headers.get("content-type") == "application/json" else {}
    return await proxy_request("analytics", f"/{path}", "POST", request, current_user, db, body)


# ============ VISION SERVICE ROUTES ============

@router.get("/vision/{path:path}")
async def vision_get(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("vision:read")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy GET requests to vision service"""
    return await proxy_request("vision", f"/{path}", "GET", request, current_user, db)


@router.post("/vision/{path:path}")
async def vision_post(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("vision:write")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy POST requests to vision service"""
    body = await request.json() if request.headers.get("content-type") == "application/json" else {}
    return await proxy_request("vision", f"/{path}", "POST", request, current_user, db, body)


@router.put("/vision/{path:path}")
async def vision_put(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("vision:write")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy PUT requests to vision service"""
    body = await request.json() if request.headers.get("content-type") == "application/json" else {}
    return await proxy_request("vision", f"/{path}", "PUT", request, current_user, db, body)


@router.delete("/vision/{path:path}")
async def vision_delete(
    path: str,
    request: Request,
    current_user: User = Depends(require_permissions("vision:delete")),
    db: AsyncSession = Depends(get_db)
):
    """Proxy DELETE requests to vision service"""
    return await proxy_request("vision", f"/{path}", "DELETE", request, current_user, db)


# ============ SERVICE HEALTH CHECKS ============

@router.get("/health")
async def check_services_health():
    """Check health of all microservices"""
    health_status = {}

    async with httpx.AsyncClient(timeout=5.0) as client:
        for service, url in SERVICE_URLS.items():
            try:
                response = await client.get(f"{url}/health")
                health_status[service] = {
                    "status": "healthy" if response.status_code == 200 else "unhealthy",
                    "url": url,
                    "response_time_ms": round(response.elapsed.total_seconds() * 1000, 2)
                }
            except Exception as e:
                health_status[service] = {
                    "status": "unavailable",
                    "url": url,
                    "error": str(e)
                }

    all_healthy = all(s["status"] == "healthy" for s in health_status.values())
    available_count = sum(1 for s in health_status.values() if s["status"] != "unavailable")

    return {
        "overall_status": "healthy" if all_healthy else ("degraded" if available_count > 0 else "down"),
        "services_available": f"{available_count}/{len(health_status)}",
        "services": health_status
    }


# ============ SERVICE INFO ============

@router.get("/info")
async def get_services_info():
    """Get information about available services"""
    return {
        "services": [
            {
                "name": "chatbot",
                "display_name": "AI Chatbot",
                "description": "Conversational AI chatbot for customer support",
                "url": SERVICE_URLS["chatbot"],
                "features": ["Multi-language", "Context-aware", "Custom training"]
            },
            {
                "name": "document",
                "display_name": "Document Intelligence",
                "description": "AI-powered document processing and analysis",
                "url": SERVICE_URLS["document"],
                "features": ["OCR", "Table extraction", "Entity recognition"]
            },
            {
                "name": "analytics",
                "display_name": "Analytics Service",
                "description": "Real-time analytics and reporting",
                "url": SERVICE_URLS["analytics"],
                "features": ["Real-time dashboards", "Custom reports", "Data export"]
            },
            {
                "name": "vision",
                "display_name": "Vision AI",
                "description": "Image analysis and processing",
                "url": SERVICE_URLS["vision"],
                "features": ["Object detection", "Text extraction", "Image classification"]
            }
        ]
    }
