from typing import Any

from fastapi import APIRouter, Body, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.deps import require_role
from app.database import get_db
from app.models.user import User
from app.schemas.common import ApiResponse
from app.schemas.product import (
    ProductCreate,
    ProvisionInterfaceCreate,
    ProvisionInterfaceResponse,
    ProvisionInterfaceUpdate,
    ProductPricingResponse,
    ProductResponse,
    ProductUpdate,
)
from app.services import product_service
from app.models.product import ProductApiType
from app.services import provision_interface_service, provision_plugin_service

router = APIRouter()
_admin = require_role("admin", "super_admin")


async def _to_response(product, pricings, db: AsyncSession) -> ProductResponse:
    base = ProductResponse.model_validate(product)
    base.pricings = [ProductPricingResponse.model_validate(p) for p in pricings]
    if product.api_type == ProductApiType.PLUGIN.value and product.api_identifier:
        try:
            manifest = provision_plugin_service.get_plugin_manifest(str(product.api_identifier))
            base.provision_plugin = provision_plugin_service.admin_manifest(manifest)
            base.product_page = base.provision_plugin.get("product_page")
        except Exception:
            base.provision_plugin = None
        if product.provision_interface_id:
            try:
                interface = await provision_interface_service.get_interface(db, int(product.provision_interface_id))
                base.provision_interface = provision_interface_service.summary(interface)
            except Exception:
                base.provision_interface = None
    return base


@router.get("", response_model=ApiResponse)
async def list_products(
    group_id: int | None = Query(None),
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    rows = await product_service.list_products(db, group_id)
    return ApiResponse(data=[await _to_response(p, pricings, db) for p, pricings in rows])


@router.get("/groups/{group_id}/readiness", response_model=ApiResponse)
async def check_group_readiness(
    group_id: int,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await product_service.check_group_readiness(db, group_id)
    return ApiResponse(data=data)


@router.get("/zjmf-finance/products", response_model=ApiResponse)
async def list_zjmf_finance_products(
    cloud_server_id: int = Query(..., description="对应魔方财务 cloud_servers.id"),
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await product_service.list_zjmf_finance_products(db, cloud_server_id)
    return ApiResponse(data=data)


@router.get("/provision-plugins", response_model=ApiResponse)
async def list_provision_plugins(_: User = Depends(_admin)):
    return ApiResponse(
        data=[
            provision_plugin_service.admin_manifest(plugin)
            for plugin in provision_plugin_service.list_plugins()
        ]
    )


@router.post("/provision-plugins/{plugin_id}/test", response_model=ApiResponse)
async def test_provision_plugin(
    plugin_id: str,
    config: dict[str, Any] | None = Body(None),
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    merged_config = dict(config or {})
    interface_id = merged_config.get("provision_interface_id") or merged_config.get("interface_id")
    if interface_id:
        item = await provision_interface_service.get_interface(db, int(interface_id))
        if item.plugin_id != plugin_id:
            raise HTTPException(status_code=400, detail="开通接口所属插件与当前插件不一致")
        merged_config.update(provision_interface_service.runtime_config(item))
    data = await provision_plugin_service.test_plugin(plugin_id, merged_config)
    return ApiResponse(data=data)


@router.get("/provision-interfaces", response_model=ApiResponse)
async def list_provision_interfaces(
    plugin_id: str | None = Query(None),
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    rows = await provision_interface_service.list_interfaces(db, plugin_id)
    return ApiResponse(
        data=[
            ProvisionInterfaceResponse.model_validate(provision_interface_service.public_interface(item)).model_dump()
            for item in rows
        ]
    )


@router.post("/provision-interfaces", response_model=ApiResponse)
async def create_provision_interface(
    data: ProvisionInterfaceCreate,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    item = await provision_interface_service.create_interface(db, data)
    return ApiResponse(
        data=ProvisionInterfaceResponse.model_validate(
            provision_interface_service.public_interface(item)
        ).model_dump()
    )


@router.put("/provision-interfaces/{interface_id}", response_model=ApiResponse)
async def update_provision_interface(
    interface_id: int,
    data: ProvisionInterfaceUpdate,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    item = await provision_interface_service.update_interface(db, interface_id, data)
    return ApiResponse(
        data=ProvisionInterfaceResponse.model_validate(
            provision_interface_service.public_interface(item)
        ).model_dump()
    )


@router.delete("/provision-interfaces/{interface_id}", response_model=ApiResponse)
async def delete_provision_interface(
    interface_id: int,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    await provision_interface_service.delete_interface(db, interface_id)
    return ApiResponse(data=None)


@router.post("/provision-interfaces/{interface_id}/test", response_model=ApiResponse)
async def test_provision_interface(
    interface_id: int,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await provision_interface_service.test_interface(db, interface_id)
    return ApiResponse(data=data)


@router.get("/zjmf-finance/product-config", response_model=ApiResponse)
async def get_zjmf_finance_product_config(
    cloud_server_id: int = Query(..., description="对应魔方财务 cloud_servers.id"),
    pid: int = Query(..., ge=1, description="魔方财务上游产品 ID"),
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await product_service.get_zjmf_finance_product_config(db, cloud_server_id, pid)
    return ApiResponse(data=data)


@router.post("", response_model=ApiResponse)
async def create_product(
    data: ProductCreate,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    product, pricings = await product_service.create_product(db, data)
    return ApiResponse(data=await _to_response(product, pricings, db))


@router.get("/{product_id}", response_model=ApiResponse)
async def get_product(
    product_id: int,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    product, pricings = await product_service.get_product(db, product_id)
    return ApiResponse(data=await _to_response(product, pricings, db))


@router.put("/{product_id}", response_model=ApiResponse)
async def update_product(
    product_id: int,
    data: ProductUpdate,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    product, pricings = await product_service.update_product(db, product_id, data)
    return ApiResponse(data=await _to_response(product, pricings, db))


@router.delete("/{product_id}", response_model=ApiResponse)
async def delete_product(
    product_id: int,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    await product_service.delete_product(db, product_id)
    return ApiResponse(data=None)


@router.get("/cloud-resources/{kind}", response_model=ApiResponse)
async def list_cloud_resources(
    kind: str,
    cloud_server_id: int = Query(..., description="对应 cloud_servers.id"),
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    """kind=image / area。供产品表单"上游绑定"区域用。"""
    items = await product_service.list_cloud_resources(db, cloud_server_id, kind)
    return ApiResponse(data=[i.model_dump() for i in items])
