from typing import Any
from datetime import datetime

from typing import Literal

from fastapi import APIRouter, Depends, HTTPException, Query, Path, Body
from pydantic import BaseModel, Field

from app.auth.keycloak_dependencies import get_current_keycloak_username
from app.services.burst_location import (
    get_burst_location_scheme_detail,
    list_burst_location_schemes,
    run_burst_location_by_network,
)

router = APIRouter()


class BurstLocationRequest(BaseModel):
    """爆管定位请求模型"""
    network: str = Field(..., description="管网名称（或数据库名称）")
    data_source: Literal["monitoring", "simulation"] = Field("monitoring", description="数据来源：monitoring（监测）或simulation（模拟）")
    pressure_scada_ids: list[str] | None = Field(None, description="压力SCADA传感器ID列表")
    burst_pressure: dict[str, float] | list[dict[str, Any]] | None = Field(None, description="爆管时的压力数据")
    normal_pressure: dict[str, float] | list[dict[str, Any]] | None = Field(None, description="正常时的压力数据")
    burst_leakage: float = Field(..., description="爆管时的漏水量")
    flow_scada_ids: list[str] | None = Field(None, description="流量SCADA传感器ID列表")
    burst_flow: dict[str, float] | list[dict[str, Any]] | None = Field(None, description="爆管时的流量数据")
    normal_flow: dict[str, float] | list[dict[str, Any]] | None = Field(None, description="正常时的流量数据")
    min_dpressure: float = Field(2.0, description="最小压力差（bar）")
    basic_pressure: float = Field(10.0, description="基准压力（bar）")
    scada_burst_start: datetime | None = Field(None, description="SCADA爆管开始时间")
    scada_burst_end: datetime | None = Field(None, description="SCADA爆管结束时间")
    use_scada_flow: bool = Field(False, description="是否使用SCADA流量数据")
    scheme_name: str | None = Field(None, description="方案名称")
    simulation_scheme_name: str | None = Field(None, description="模拟方案名称")
    simulation_scheme_type: str | None = Field(None, description="模拟方案类型")


@router.post(
    "/locate/",
    summary="执行爆管定位",
    description="基于压力和流量数据定位管网中的爆管位置"
)
async def locate_burst(
    data: BurstLocationRequest = Body(..., description="爆管定位请求数据"),
    username: str = Depends(get_current_keycloak_username),
) -> dict[str, Any]:
    """
    执行爆管定位分析。
    
    使用压力和流量SCADA数据，通过对比爆管和正常状态下的数据差异，
    定位管网中的爆管位置。
    
    Args:
        data: 包含管网名称（或数据库名称）、压力、流量数据及相关参数的请求体
        username: 当前认证用户名
        
    Returns:
        包含定位结果的字典
        
    Raises:
        HTTPException: 当数据类型或值不正确时
    """
    try:
        return run_burst_location_by_network(**data.model_dump(), username=username)
    except (TypeError, ValueError) as exc:
        raise HTTPException(status_code=400, detail=str(exc))


@router.get(
    "/schemes/",
    summary="查询爆管定位方案列表",
    description="获取指定网络的所有爆管定位方案"
)
async def query_burst_schemes(
    network: str = Query(..., description="管网名称（或数据库名称）"),
    query_date: datetime | None = Query(None, description="查询日期（可选）")
) -> list[dict[str, Any]]:
    """
    获取爆管定位方案列表。
    
    查询指定网络的所有已配置的爆管定位方案，
    可按日期进行筛选。
    
    Args:
        network: 管网名称（或数据库名称）
        query_date: 查询日期（可选）
        
    Returns:
        爆管定位方案列表
        
    Raises:
        HTTPException: 当查询失败时
    """
    try:
        return list_burst_location_schemes(network=network, query_date=query_date)
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc))


@router.get(
    "/schemes/{scheme_name}",
    summary="获取爆管定位方案详情",
    description="获取指定爆管定位方案的详细信息"
)
async def query_burst_scheme_detail(
    network: str = Query(..., description="管网名称（或数据库名称）"),
    scheme_name: str = Path(..., description="爆管定位方案名称")
) -> dict[str, Any]:
    """
    获取爆管定位方案详情。
    
    查询指定爆管定位方案的完整配置和参数信息。
    
    Args:
        network: 管网名称（或数据库名称）
        scheme_name: 爆管定位方案名称
        
    Returns:
        包含方案详情的字典
        
    Raises:
        HTTPException: 当查询失败时
    """
    try:
        return get_burst_location_scheme_detail(network=network, scheme_name=scheme_name)
    except Exception as exc:
        raise HTTPException(status_code=400, detail=str(exc))
