"""
Service Configuration API
Manage service configurations and credentials for clients
"""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any, List
from datetime import datetime
import structlog

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.service_config import (
    ServiceConfig, ServiceCredential, ServiceType, DEFAULT_SERVICE_CONFIGS
)

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


# ============ SCHEMAS ============

class ServiceConfigCreate(BaseModel):
    service_type: ServiceType
    ai_provider: Optional[str] = "openai"
    ai_model: Optional[str] = "gpt-4"
    settings: Optional[Dict[str, Any]] = None
    branding: Optional[Dict[str, Any]] = None
    daily_limit: Optional[int] = None
    monthly_limit: Optional[int] = None
    rate_limit_per_minute: Optional[int] = 60
    webhook_url: Optional[str] = None
    webhook_events: Optional[List[str]] = []


class ServiceConfigUpdate(BaseModel):
    is_enabled: Optional[bool] = None
    ai_provider: Optional[str] = None
    ai_model: Optional[str] = None
    settings: Optional[Dict[str, Any]] = None
    branding: Optional[Dict[str, Any]] = None
    daily_limit: Optional[int] = None
    monthly_limit: Optional[int] = None
    rate_limit_per_minute: Optional[int] = None
    webhook_url: Optional[str] = None
    webhook_events: Optional[List[str]] = None


class ServiceConfigResponse(BaseModel):
    id: str
    client_id: str
    service_type: str
    is_enabled: bool
    is_active: bool
    ai_provider: Optional[str]
    ai_model: Optional[str]
    settings: Dict[str, Any]
    branding: Dict[str, Any]
    daily_limit: Optional[int]
    monthly_limit: Optional[int]
    rate_limit_per_minute: int
    webhook_url: Optional[str]
    webhook_events: List[str]
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True


class ServiceCredentialCreate(BaseModel):
    service_type: ServiceType
    provider: str
    credential_type: str = "api_key"
    credentials: Dict[str, str]  # {"api_key": "xxx"} or {"client_id": "x", "client_secret": "y"}
    name: Optional[str] = None
    description: Optional[str] = None


class ServiceCredentialResponse(BaseModel):
    id: str
    service_type: str
    provider: str
    credential_type: str
    is_active: bool
    is_verified: bool
    name: Optional[str]
    description: Optional[str]
    created_at: datetime
    last_verified_at: Optional[datetime]

    class Config:
        from_attributes = True


# ============ SERVICE CONFIGURATIONS ============

@router.get("/configs", response_model=List[ServiceConfigResponse])
async def list_service_configs(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Get all service configurations for the current client"""
    query = select(ServiceConfig).where(
        ServiceConfig.client_id == current_user.client_id
    )
    result = await db.execute(query)
    configs = result.scalars().all()
    return configs


@router.get("/configs/{service_type}", response_model=ServiceConfigResponse)
async def get_service_config(
    service_type: ServiceType,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Get configuration for a specific service"""
    query = select(ServiceConfig).where(
        ServiceConfig.client_id == current_user.client_id,
        ServiceConfig.service_type == service_type
    )
    result = await db.execute(query)
    config = result.scalar_one_or_none()

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Configuration for {service_type.value} not found"
        )

    return config


@router.post("/configs", response_model=ServiceConfigResponse)
async def create_service_config(
    data: ServiceConfigCreate,
    current_user: User = Depends(require_permissions("service:write")),
    db: AsyncSession = Depends(get_db)
):
    """Create a new service configuration"""
    # Check if config already exists
    existing = await db.execute(
        select(ServiceConfig).where(
            ServiceConfig.client_id == current_user.client_id,
            ServiceConfig.service_type == data.service_type
        )
    )
    if existing.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Configuration for {data.service_type.value} already exists"
        )

    # Get default config and merge with provided settings
    defaults = DEFAULT_SERVICE_CONFIGS.get(data.service_type, {})
    settings = {**defaults.get("settings", {}), **(data.settings or {})}
    branding = {**defaults.get("branding", {}), **(data.branding or {})}

    config = ServiceConfig(
        client_id=current_user.client_id,
        service_type=data.service_type,
        ai_provider=data.ai_provider or defaults.get("ai_provider", "openai"),
        ai_model=data.ai_model or defaults.get("ai_model", "gpt-4"),
        settings=settings,
        branding=branding,
        daily_limit=data.daily_limit,
        monthly_limit=data.monthly_limit,
        rate_limit_per_minute=data.rate_limit_per_minute,
        webhook_url=data.webhook_url,
        webhook_events=data.webhook_events or []
    )

    db.add(config)
    await db.commit()
    await db.refresh(config)

    logger.info("Service config created",
                client_id=current_user.client_id,
                service_type=data.service_type.value)

    return config


@router.put("/configs/{service_type}", response_model=ServiceConfigResponse)
async def update_service_config(
    service_type: ServiceType,
    data: ServiceConfigUpdate,
    current_user: User = Depends(require_permissions("service:write")),
    db: AsyncSession = Depends(get_db)
):
    """Update service configuration"""
    query = select(ServiceConfig).where(
        ServiceConfig.client_id == current_user.client_id,
        ServiceConfig.service_type == service_type
    )
    result = await db.execute(query)
    config = result.scalar_one_or_none()

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Configuration for {service_type.value} not found"
        )

    # Update fields
    update_data = data.model_dump(exclude_unset=True)
    for field, value in update_data.items():
        if field == "settings" and value:
            # Merge settings instead of replacing
            config.settings = {**config.settings, **value}
        elif field == "branding" and value:
            # Merge branding instead of replacing
            config.branding = {**config.branding, **value}
        else:
            setattr(config, field, value)

    await db.commit()
    await db.refresh(config)

    logger.info("Service config updated",
                client_id=current_user.client_id,
                service_type=service_type.value)

    return config


@router.delete("/configs/{service_type}")
async def delete_service_config(
    service_type: ServiceType,
    current_user: User = Depends(require_permissions("service:delete")),
    db: AsyncSession = Depends(get_db)
):
    """Delete service configuration"""
    query = select(ServiceConfig).where(
        ServiceConfig.client_id == current_user.client_id,
        ServiceConfig.service_type == service_type
    )
    result = await db.execute(query)
    config = result.scalar_one_or_none()

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Configuration for {service_type.value} not found"
        )

    await db.delete(config)
    await db.commit()

    return {"message": f"Configuration for {service_type.value} deleted"}


@router.post("/configs/{service_type}/reset")
async def reset_service_config(
    service_type: ServiceType,
    current_user: User = Depends(require_permissions("service:write")),
    db: AsyncSession = Depends(get_db)
):
    """Reset service configuration to defaults"""
    query = select(ServiceConfig).where(
        ServiceConfig.client_id == current_user.client_id,
        ServiceConfig.service_type == service_type
    )
    result = await db.execute(query)
    config = result.scalar_one_or_none()

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Configuration for {service_type.value} not found"
        )

    # Reset to defaults
    defaults = DEFAULT_SERVICE_CONFIGS.get(service_type, {})
    config.settings = defaults.get("settings", {})
    config.branding = defaults.get("branding", {})
    config.ai_provider = defaults.get("ai_provider", "openai")
    config.ai_model = defaults.get("ai_model", "gpt-4")

    await db.commit()
    await db.refresh(config)

    return config


# ============ SERVICE CREDENTIALS ============

@router.get("/credentials", response_model=List[ServiceCredentialResponse])
async def list_credentials(
    service_type: Optional[ServiceType] = None,
    current_user: User = Depends(require_permissions("credentials:read")),
    db: AsyncSession = Depends(get_db)
):
    """List all credentials for the current client"""
    query = select(ServiceCredential).where(
        ServiceCredential.client_id == current_user.client_id
    )
    if service_type:
        query = query.where(ServiceCredential.service_type == service_type)

    result = await db.execute(query)
    credentials = result.scalars().all()
    return credentials


@router.post("/credentials", response_model=ServiceCredentialResponse)
async def create_credential(
    data: ServiceCredentialCreate,
    current_user: User = Depends(require_permissions("credentials:write")),
    db: AsyncSession = Depends(get_db)
):
    """Add a new credential"""
    # TODO: Encrypt credentials before storing
    credential = ServiceCredential(
        client_id=current_user.client_id,
        service_type=data.service_type,
        provider=data.provider,
        credential_type=data.credential_type,
        credentials=data.credentials,  # Should be encrypted
        name=data.name,
        description=data.description
    )

    db.add(credential)
    await db.commit()
    await db.refresh(credential)

    logger.info("Credential created",
                client_id=current_user.client_id,
                provider=data.provider)

    return credential


@router.delete("/credentials/{credential_id}")
async def delete_credential(
    credential_id: str,
    current_user: User = Depends(require_permissions("credentials:delete")),
    db: AsyncSession = Depends(get_db)
):
    """Delete a credential"""
    query = select(ServiceCredential).where(
        ServiceCredential.id == credential_id,
        ServiceCredential.client_id == current_user.client_id
    )
    result = await db.execute(query)
    credential = result.scalar_one_or_none()

    if not credential:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Credential not found"
        )

    await db.delete(credential)
    await db.commit()

    return {"message": "Credential deleted"}


@router.post("/credentials/{credential_id}/verify")
async def verify_credential(
    credential_id: str,
    current_user: User = Depends(require_permissions("credentials:write")),
    db: AsyncSession = Depends(get_db)
):
    """Verify a credential by testing the connection"""
    query = select(ServiceCredential).where(
        ServiceCredential.id == credential_id,
        ServiceCredential.client_id == current_user.client_id
    )
    result = await db.execute(query)
    credential = result.scalar_one_or_none()

    if not credential:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Credential not found"
        )

    # TODO: Implement actual verification based on provider
    # For now, just mark as verified
    credential.is_verified = True
    credential.last_verified_at = datetime.utcnow()

    await db.commit()

    return {"message": "Credential verified successfully", "is_verified": True}


# ============ INITIALIZE CLIENT SERVICES ============

@router.post("/initialize")
async def initialize_client_services(
    services: List[ServiceType],
    current_user: User = Depends(require_permissions("service:write")),
    db: AsyncSession = Depends(get_db)
):
    """
    Initialize service configurations for a client
    Creates default configs for specified services
    """
    created = []
    skipped = []

    for service_type in services:
        # Check if already exists
        existing = await db.execute(
            select(ServiceConfig).where(
                ServiceConfig.client_id == current_user.client_id,
                ServiceConfig.service_type == service_type
            )
        )
        if existing.scalar_one_or_none():
            skipped.append(service_type.value)
            continue

        # Create with defaults
        defaults = DEFAULT_SERVICE_CONFIGS.get(service_type, {})
        config = ServiceConfig(
            client_id=current_user.client_id,
            service_type=service_type,
            ai_provider=defaults.get("ai_provider", "openai"),
            ai_model=defaults.get("ai_model", "gpt-4"),
            settings=defaults.get("settings", {}),
            branding=defaults.get("branding", {})
        )
        db.add(config)
        created.append(service_type.value)

    await db.commit()

    return {
        "message": "Services initialized",
        "created": created,
        "skipped": skipped
    }
