from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from src.core.database import get_db
from src.apps.auth.utils.auth import get_current_merchant, get_current_superuser
from src.apps.payment_providers import services, crud
from src.apps.payment_providers.schemas.requests import (
    OnboardingSubmitRequest,
    AdminCreateProviderRequest,
    AdminUpdateProviderRequest,
    AdminAssignProviderRequest,
    AdminUpdateMerchantProviderRequest,
    IframeConfigRequest,
)
from src.apps.payment_providers.schemas.responses import (
    PaymentProviderResponse,
    OnboardingStateResponse,
    SelectProviderResponse,
    MessageResponse,
    AdminMerchantProviderConfigResponse,
)
from typing import List, Dict, Any
from src.core.exceptions import NotFoundError

router = APIRouter()


# ─── Merchant-Facing Endpoints ──────────────────────────────────────────────

@router.get("", response_model=Dict[str, Any])
async def list_merchant_providers(
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """List all payment providers available to the current merchant."""
    result = services.get_providers_for_merchant(merchant, db)
    return {
        "data": [item.model_dump() for item in result],
        "status_code": 200,
        "success": True,
        "message": "Payment providers fetched successfully",
    }


@router.get("/active", response_model=Dict[str, Any])
async def get_active_provider(
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Get the merchant's currently active payment provider."""
    result = services.get_active_provider_for_merchant(merchant, db)
    if not result:
        raise NotFoundError(message="No active provider configured.")
    return {
        "data": result.model_dump(),
        "status_code": 200,
        "success": True,
        "message": "Active payment provider fetched successfully",
    }


@router.post("/iframe-config", response_model=Dict[str, Any])
async def get_iframe_config_endpoint(
    payload: IframeConfigRequest,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Get iframe configuration for the merchant's active payment provider."""
    from src.core.providers.factory import get_provider_for_merchant
    from src.apps.payment_providers.schemas.responses import IframeConfigResponse
    provider, config = await get_provider_for_merchant(merchant, db)
    iframe_cfg = provider.get_iframe_config(config, payload.amount, payload.currency)
    return {
        "data": IframeConfigResponse(
            provider_slug=config.provider_slug,
            sdk_url=iframe_cfg.sdk_url,
            api_key=iframe_cfg.api_key,
            merchant_id=iframe_cfg.merchant_id,
            mode=iframe_cfg.mode,
            extra=iframe_cfg.extra,
        ).model_dump(),
        "status_code": 200,
        "success": True,
        "message": "Iframe config fetched successfully",
    }


@router.post("/{provider_id}/select", response_model=Dict[str, Any])
async def select_provider(
    provider_id: int,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Set a provider as the merchant's active provider."""
    result = services.select_active_provider(merchant, provider_id, db)
    db.commit()
    return {
        "data": result.model_dump(),
        "status_code": 200,
        "success": True,
        "message": "Active provider updated successfully",
    }


@router.get("/{provider_id}/onboarding", response_model=Dict[str, Any])
async def get_onboarding(
    provider_id: int,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Get the onboarding state for a merchant + provider."""
    result = services.get_onboarding_state(merchant, provider_id, db)
    return {
        "data": result.model_dump(),
        "status_code": 200,
        "success": True,
        "message": "Onboarding state fetched successfully",
    }


@router.post("/{provider_id}/onboarding", response_model=Dict[str, Any])
async def submit_onboarding(
    provider_id: int,
    payload: OnboardingSubmitRequest,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Submit onboarding credentials for a provider."""
    result = await services.submit_onboarding(merchant, provider_id, payload.credentials, db)
    db.commit()
    return {
        "data": result.model_dump(),
        "status_code": 200,
        "success": True,
        "message": "Onboarding credentials submitted successfully",
    }


@router.delete("/{provider_id}/credentials", status_code=204)
async def remove_credentials(
    provider_id: int,
    merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """Remove credentials and reset onboarding for a provider."""
    services.remove_provider_credentials(merchant, provider_id, db)
    db.commit()


# ─── Admin Endpoints ─────────────────────────────────────────────────────────

@router.get("/admin/master", response_model=Dict[str, Any])
async def admin_list_providers(
    _=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Admin: list all master providers."""
    providers = crud.get_all_providers(db)
    data = [
        PaymentProviderResponse(
            id=p.id, name=p.name, slug=p.slug, description=p.description,
            logo_url=p.logo_url, is_active=p.is_active, is_default=p.is_default,
            supported_payment_methods=p.supported_payment_methods,
        ).model_dump()
        for p in providers
    ]
    return {
        "data": data,
        "status_code": 200,
        "success": True,
        "message": "Payment providers fetched successfully",
    }


@router.post("/admin/master", response_model=Dict[str, Any], status_code=201)
async def admin_create_provider(
    payload: AdminCreateProviderRequest,
    _=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Admin: create a new master provider."""
    provider = services.create_provider(payload, db)
    db.commit()
    return {
        "data": PaymentProviderResponse(
            id=provider.id, name=provider.name, slug=provider.slug,
            description=provider.description, logo_url=provider.logo_url,
            is_active=provider.is_active, is_default=provider.is_default,
            supported_payment_methods=provider.supported_payment_methods,
        ).model_dump(),
        "status_code": 201,
        "success": True,
        "message": "Payment provider created successfully",
    }


@router.patch("/admin/master/{provider_id}", response_model=Dict[str, Any])
async def admin_update_provider(
    provider_id: int,
    payload: AdminUpdateProviderRequest,
    _=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Admin: update a master provider."""
    provider = services.admin_update_provider(provider_id, payload, db)
    db.commit()
    db.refresh(provider)
    return {
        "data": PaymentProviderResponse(
            id=provider.id, name=provider.name, slug=provider.slug,
            description=provider.description, logo_url=provider.logo_url,
            is_active=provider.is_active, is_default=provider.is_default,
            supported_payment_methods=provider.supported_payment_methods,
        ).model_dump(),
        "status_code": 200,
        "success": True,
        "message": "Payment provider updated successfully",
    }


@router.get("/admin/merchants/{merchant_id}/providers", response_model=Dict[str, Any])
async def admin_list_merchant_providers(
    merchant_id: int,
    _=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Admin: list all providers and their config for a merchant."""
    result = services.admin_list_merchant_providers(merchant_id, db)
    return {
        "data": [item.model_dump() for item in result],
        "status_code": 200,
        "success": True,
        "message": "Merchant payment providers fetched successfully",
    }


@router.post("/admin/merchants/{merchant_id}/providers/{provider_id}/assign", response_model=Dict[str, Any], status_code=201)
async def admin_assign_provider(
    merchant_id: int,
    provider_id: int,
    payload: AdminAssignProviderRequest,
    _=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Admin: assign a provider to a merchant. Does not reset onboarding_status if already configured."""
    result = services.admin_assign_provider_to_merchant(merchant_id, provider_id, payload, db)
    db.commit()
    return {
        "data": result,
        "status_code": 201,
        "success": True,
        "message": result.get("message", "Provider assigned successfully"),
    }


@router.patch("/admin/merchants/{merchant_id}/providers/{provider_id}", response_model=Dict[str, Any])
async def admin_update_merchant_provider(
    merchant_id: int,
    provider_id: int,
    payload: AdminUpdateMerchantProviderRequest,
    _=Depends(get_current_superuser),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    """Admin: update a merchant's provider config."""
    mc = crud.get_merchant_provider_config(merchant_id, provider_id, db)
    if not mc:
        raise NotFoundError(message="Merchant provider config not found.")
    if payload.is_enabled is not None:
        mc.is_active = payload.is_enabled
    if payload.onboarding_status is not None:
        mc.onboarding_status = payload.onboarding_status
    db.commit()
    return {
        "data": {"message": "Merchant provider config updated."},
        "status_code": 200,
        "success": True,
        "message": "Merchant provider config updated successfully",
    }
