from __future__ import annotations

from dataclasses import dataclass
import math
import re

from .core import HydrologyError, _linear_interpolate_clamped, _require_positive, _safe_round


@dataclass(frozen=True)
class ScourMethodDefinition:
    key: str
    category: str
    name: str
    source: str
    formula: str
    parameters: tuple[tuple[str, str, str], ...]
    note: str = ""


@dataclass(frozen=True)
class ScourCalculationInput:
    method_key: str
    parameters: dict[str, float]


@dataclass(frozen=True)
class ScourCalculationResult:
    method_key: str
    method_name: str
    category: str
    source: str
    formula: str
    result_name: str
    result_value: float
    unit: str
    rows: tuple[tuple[str, str, str], ...]
    note: str


SCOUR_BETA_BY_ANGLE = [
    (15.0, 1.00),
    (20.0, 1.25),
    (30.0, 1.50),
    (40.0, 1.75),
    (50.0, 2.00),
    (60.0, 2.25),
    (70.0, 2.50),
    (80.0, 2.75),
    (90.0, 3.00),
]

SCOUR_E_BY_SEDIMENT = {
    "含沙量<1": 0.46,
    "含沙量1~10": 0.66,
    "含沙量>10": 0.86,
}

SCOUR_CLAY_EQUIVALENT_PARTICLE_TABLE = [
    ("不密实的", "0.9~1.2", "11.76", "1", "0.5", "0.5"),
    ("中等密实的", "0.6~0.9", "11.76~15.68", "4", "2", "2"),
    ("密实的", "0.3~0.6", "15.68~19.60", "8", "8", "3"),
    ("很密实的", "0.2~0.3", "19.60~21.07", "10", "10", "6"),
]

SCOUR_NONCOHESIVE_VH1_TABLE = [
    ("细砂", "0.05~0.25", "0.35~0.32"),
    ("中砂", "0.25~0.50", "0.32~0.40"),
    ("粗砂", "0.50~2.00", "0.40~0.60"),
    ("小圆砾", "2.00~5.00", "0.60~0.90"),
    ("中圆砾", "5.00~10.00", "0.90~1.20"),
    ("大圆砾", "10~20", "1.20~1.50"),
    ("小卵石", "20~40", "1.50~2.00"),
    ("中卵石", "40~60", "2.00~2.30"),
    ("大卵石", "60~200", "2.30~3.60"),
    ("小漂石", "200~400", "3.60~4.70"),
    ("中漂石", "400~800", "4.70~6.00"),
    ("大漂石", ">800", ">6.00"),
]


SCOUR_METHODS: tuple[ScourMethodDefinition, ...] = (
    ScourMethodDefinition(
        "slt_parallel_bank",
        "堤岸/护岸冲刷",
        "SLT 808 A.3.4-1 水流平行岸坡局部冲刷",
        "SLT 808-2025 A.3.4-1",
        "hB = hp * ((vp / vH)^n - 1)",
        (
            ("hp", "冲刷处水深，m", "3.0"),
            ("vp", "建成后计算水位时主河槽平均流速，m/s", "2.5"),
            ("vH", "河床允许不冲流速，m/s", "1.5"),
            ("n", "与防护岸坡平面形状有关，一般取1/4", "0.25"),
        ),
        "当vp<=vH时计算值可按0处理。",
    ),
    ScourMethodDefinition(
        "slt_oblique_bank",
        "堤岸/护岸冲刷",
        "SLT 808 A.3.4-2 水流斜冲防护岸坡冲刷",
        "SLT 808-2025 A.3.4-2~A.3.4-4",
        "Δhp = 23*tan(alpha/2)*Vj^2/(sqrt(1+m^2)*g) - 30*d；Vj按滩地/无滩地公式或手动输入",
        (
            ("alpha_deg", "水流流向与岸坡夹角α，度", "30"),
            ("vj_mode", "Vj计算方式：1=滩地河床；2=无滩地河床；0=手动输入Vj", "1"),
            ("Vj", "手动输入的水流局部冲刷流速，m/s；vj_mode=0时使用", "2.5"),
            ("Q1", "滩地公式：通过河滩部分的设计流量，m3/s", "100"),
            ("B1", "滩地公式：河滩宽度，从河槽边缘至坡脚距离，m", "50"),
            ("H1", "滩地公式：河滩水深，m", "2.0"),
            ("Q", "无滩地公式：设计流量，m3/s", "500"),
            ("W", "无滩地公式：原河道过水断面面积，m2", "300"),
            ("Wp", "无滩地公式：河道缩窄部分断面面积，m2", "40"),
            ("m", "防护建筑物迎水面边坡系数", "1.5"),
            ("d", "坡脚土壤计算粒径，m", "0.02"),
            ("g", "重力加速度，m/s2", "9.81"),
        ),
        "负值按0处理；d按导则说明取相应计算粒径。Vj在本公式内按A.3.4-3/A.3.4-4自动计算或手动输入。",
    ),
    ScourMethodDefinition(
        "slt_wetland_vj",
        "堤岸/护岸冲刷",
        "SLT 808 A.3.4-3 滩地河床局部冲刷流速Vj",
        "SLT 808-2025 A.3.4-3及表A.3.4-2",
        "Vj = Q1/(B1*H1) * 2β/(1+β)",
        (
            ("Q1", "通过河滩部分的设计流量，m3/s", "100"),
            ("B1", "河滩宽度，从河槽边缘至坡脚距离，m", "50"),
            ("H1", "河滩水深，m", "2.0"),
            ("alpha_deg", "水流流向与岸坡夹角，度；用于查β", "30"),
        ),
        "β按角度线性插值：15°为1.00，90°为3.00。",
    ),
    ScourMethodDefinition(
        "slt_no_floodplain_vj",
        "堤岸/护岸冲刷",
        "SLT 808 A.3.4-4 无滩地河床局部冲刷流速Vj",
        "SLT 808-2025 A.3.4-4",
        "Vj = Q / (W - Wp)",
        (
            ("Q", "设计流量，m3/s", "500"),
            ("W", "原河道过水断面面积，m2", "300"),
            ("Wp", "河道缩窄部分断面面积，m2", "40"),
        ),
        "W必须大于Wp。",
    ),
    ScourMethodDefinition(
        "slt_groyne_non_submerged",
        "丁坝/挑流建筑物冲刷",
        "SLT 808 A.3.4-5 非淹没丁坝冲刷深度",
        "SLT 808-2025 A.3.4-5~A.3.4-7",
        "ΔH = 27*K1*K2*tan(alpha/2)*v^2/g - 30*d；K1=e^(-5.1*sqrt(v^2/(g*l)))；K2=e^(-0.2*m)",
        (
            ("alpha_deg", "α：水流轴线与丁坝轴线交角，度；上挑α>90°时取tan(α/2)=1", "60"),
            ("v", "丁坝前水流的行近流速，m/s", "2.5"),
            ("l", "l：丁坝在水流法线上的投影长度，m，用于计算K1", "10"),
            ("m", "丁坝边坡坡率，用于计算K2", "1.5"),
            ("d", "河床沙粒粒径，m", "0.02"),
            ("g", "重力加速度，m/s2", "9.81"),
        ),
        "负值按0处理。",
    ),
    ScourMethodDefinition(
        "slt_groyne_fine_bed",
        "丁坝/挑流建筑物冲刷",
        "SLT 808 A.3.4-8 非淹没丁坝细颗粒河床局部冲刷",
        "SLT 808-2025 A.3.4-8",
        "hB = h0 + 2.8*v^2/sqrt(1+m^2)*sin(alpha)",
        (
            ("h0", "行近水流水深，m", "3.0"),
            ("v", "行近水流流速，m/s", "2.0"),
            ("m", "边坡系数", "1.5"),
            ("alpha_deg", "α：水流与丁坝交角，度", "60"),
        ),
        "导则式中未列g项，按原式计算。",
    ),
    ScourMethodDefinition(
        "jtg_64_1_nonc_channel",
        "桥下一般冲刷",
        "JTG C30 64-1 修正式/SLT 808 A.3.5-1 非粘性土河槽一般冲刷",
        "JTG C30-2015 64-1修正式；SLT 808-2025 A.3.5-1~A.3.5-3",
        "hp = [ A*(Qc/(mu*Bc))*(hmc/hc)^(5/3)/(E*dc^(1/6)) ]^(3/5)，A=(sqrt(Bd)/H)^0.15",
        (
            ("Qc", "桥下河槽部分通过的设计流量，m3/s", "500"),
            ("mu", "桥墩水流侧向压缩系数，无资料可先取1.0", "1.0"),
            ("Bc", "桥下河槽部分桥孔过水净宽，m", "80"),
            ("hmc", "桥下河槽部分最大水深，m", "5.0"),
            ("hc", "桥下河槽部分平均水深，m", "3.0"),
            ("E", "与汛期含沙量有关的系数，表A.3.5可取0.46/0.66/0.86", "0.66"),
            ("dc", "河槽土平均粒径，mm", "1.0"),
            ("Bd", "造床流量时河宽，m", "100"),
            ("H", "造床流量时平均水深，m", "3.0"),
        ),
        "dc按mm输入；A过大时按规范说明可控制不超过1.8。",
    ),
    ScourMethodDefinition(
        "jtg_64_2_nonc_simplified",
        "桥下一般冲刷",
        "JTG C30 64-2 简化式（非粘性土河槽一般冲刷）",
        "JTG C30-2015 8.3.1-1~8.3.1-3（64-2简化式）",
        "hp = 1.04*(Ad*Q2/Qc)^0.90*[Bc/((1-lambda)*mu*Bcg)]^0.66*hcm；"
        "Q2=Qc/(Qc+Qt1)*Qp；Ad=(sqrt(Bz)/Hz)^0.15",
        (
            ("Qp", "设计流量，m3/s", "650"),
            ("Qc", "天然状态下河槽部分设计流量，m3/s", "500"),
            ("Qt1", "天然状态下桥下河滩部分设计流量，m3/s", "150"),
            ("Bc", "天然状态下河槽宽度，m", "100"),
            ("Bcg", "桥长范围内河槽宽度；扩宽至全桥时取桥孔总长度，m", "80"),
            ("lambda", "桥墩阻水总面积与Bcg范围过水面积之比，0~1", "0.05"),
            ("mu", "桥墩水流侧向压缩系数，按表8.3.1-1取值", "0.97"),
            ("hcm", "天然状态下河槽最大水深，m", "5.0"),
            ("Bz", "造床流量下河槽宽度，m", "100"),
            ("Hz", "造床流量下河槽平均水深，m", "3.0"),
        ),
        "Q2和Ad由程序自动计算；山前变迁、游荡、宽滩河段Ad>1.8时可按1.8采用。lambda必须按设计水位下桥墩阻水面积计算。",
    ),
    ScourMethodDefinition(
        "slt_bridge_nonc_floodplain",
        "桥下一般冲刷",
        "SLT 808 A.3.5-4 非粘性土河滩及人工渠道一般冲刷",
        "SLT 808-2025 A.3.5-4~A.3.5-5",
        "hp = [ At*(Qt/Bt)*(hmt/ht)^(5/3)/VH1 ]^(5/6)",
        (
            ("At", "河滩流量非均匀分配系数，1.0~1.15", "1.05"),
            ("Qt", "桥下河滩部分通过的设计流量，m3/s", "100"),
            ("Bt", "桥下河滩部分桥孔过水净宽，m", "40"),
            ("hmt", "桥下河滩最大水深，m", "2.0"),
            ("ht", "桥下河滩平均水深，m", "1.2"),
            ("VH1", "水深1m时非粘性土不冲刷流速，m/s", "0.8"),
        ),
    ),
    ScourMethodDefinition(
        "slt_bridge_cohesive_channel",
        "桥下一般冲刷",
        "SLT 808 A.3.5-6 粘性土河槽一般冲刷",
        "SLT 808-2025 A.3.5-6",
        "hp = [ A*(Qc/Bc)*(hmc/hc)^(5/3)/(0.33*(1/IL)) ]^(5/8)",
        (
            ("A", "单宽流量集中系数，1.0~1.2", "1.1"),
            ("Qc", "桥下河槽部分通过的设计流量，m3/s", "500"),
            ("Bc", "桥下河槽部分桥孔过水净宽，m", "80"),
            ("hmc", "桥下河槽部分最大水深，m", "5.0"),
            ("hc", "桥下河槽部分平均水深，m", "3.0"),
            ("IL", "冲刷范围内粘性土样液性指数，0.16~1.19", "0.6"),
        ),
    ),
    ScourMethodDefinition(
        "slt_bridge_cohesive_floodplain",
        "桥下一般冲刷",
        "SLT 808 A.3.5-7 粘性土河滩一般冲刷",
        "SLT 808-2025 A.3.5-7",
        "hp = [ (Qt/Bt)*(hmt/ht)^(5/3)/(0.33*(1/IL)) ]^(6/7)",
        (
            ("Qt", "桥下河滩部分通过的设计流量，m3/s", "100"),
            ("Bt", "桥下河滩部分桥孔过水净宽，m", "40"),
            ("hmt", "桥下河滩最大水深，m", "2.0"),
            ("ht", "桥下河滩平均水深，m", "1.2"),
            ("IL", "冲刷范围内粘性土样液性指数，0.16~1.19", "0.6"),
        ),
    ),
    ScourMethodDefinition(
        "jtg_65_nonc_pier_auto",
        "桥墩局部冲刷",
        "JTG C30 65-1/65-2 非粘性土桥墩局部冲刷自动判别",
        "JTG C30-2015 65-1、65-2；SLT 808-2025 A.3.5-8~A.3.5-12",
        "v<=v0: hb=Kξ*Kη*B1^0.6*(v-v0')；v>v0: hb=Kξ*Kη*B1^0.6*(v-v0')*((v-v0')/(v0-v0'))^n",
        (
            ("Kxi", "墩形系数Kξ", "1.0"),
            ("B1", "桥墩计算宽度，m", "2.0"),
            ("v", "一般冲刷后墩前行近流速，m/s", "2.5"),
            ("hp", "一般冲刷后水深，m", "5.0"),
            ("d", "河床土平均粒径，mm", "1.0"),
        ),
        "自动计算v0、Kη、v0'、n并按v与v0判别采用65-1或65-2。",
    ),
    ScourMethodDefinition(
        "jtg_65_2_nonc_pier_original",
        "桥墩局部冲刷",
        "JTG C30 65-2 原式（非粘性土桥墩局部冲刷）",
        "JTG C30-2015 65-2；SLT 808-2025 A.3.5-8~A.3.5-12对应原式",
        "v≤v0: hb=Kξ*Kη2*B1^0.6*hp^0.15*((v-v0')/v0)；v>v0: hb=Kξ*Kη2*B1^0.6*hp^0.15*((v-v0')/v0)^n2",
        (
            ("Kxi", "墩形系数Kξ，按墩形查规范附录表", "1.0"),
            ("B1", "桥墩计算宽度，m", "2.0"),
            ("v", "一般冲刷后墩前行近流速，m/s", "2.5"),
            ("hp", "一般冲刷后水深，m", "5.0"),
            ("d", "河床泥沙平均粒径，mm", "1.0"),
        ),
        "该项为65-2原式；65-1修正式已在上一项中自动判别。",
    ),
    ScourMethodDefinition(
        "slt_pier_cohesive_auto",
        "桥墩局部冲刷",
        "SLT 808 A.3.5-13/14 粘性土桥墩局部冲刷自动判别",
        "SLT 808-2025 A.3.5-13~A.3.5-14",
        "hp/B1>=2.5: hb=0.83*Kξ*B1^0.6*IL^1.25*v；hp/B1<2.5: hb=0.55*Kξ*B1^0.6*hp^0.1*IL*v",
        (
            ("Kxi", "墩形系数Kξ", "1.0"),
            ("B1", "桥墩计算宽度，m", "2.0"),
            ("hp", "一般冲刷后水深，m", "5.0"),
            ("IL", "冲刷范围内粘性土样液性指数，0.16~1.48", "0.6"),
            ("v", "一般冲刷后墩前行近流速，m/s", "2.0"),
        ),
    ),
)

SCOUR_METHOD_MAP = {item.key: item for item in SCOUR_METHODS}


def scour_method_parameter_text(method_key: str) -> str:
    method = SCOUR_METHOD_MAP[method_key]
    return "\n".join(f"{key} = {default}    # {desc}" for key, desc, default in method.parameters)


def parse_key_value_parameters(text: str) -> dict[str, float]:
    params: dict[str, float] = {}
    for raw_line in text.splitlines():
        line = raw_line.split("#", 1)[0].strip()
        if not line:
            continue
        if "=" in line:
            key, value = line.split("=", 1)
        else:
            parts = re.split(r"[,，\s]+", line, maxsplit=1)
            if len(parts) != 2:
                raise HydrologyError(f"参数行格式错误：{raw_line}")
            key, value = parts
        key = key.strip()
        value = value.strip()
        try:
            params[key] = float(value)
        except ValueError as exc:
            raise HydrologyError(f"参数 {key} 必须是数字：{value}") from exc
    return params


def _param(params: dict[str, float], key: str) -> float:
    if key not in params:
        raise HydrologyError(f"缺少冲刷计算参数：{key}")
    return float(params[key])


def _positive(params: dict[str, float], key: str) -> float:
    return _require_positive(key, _param(params, key))


def _angle_beta(alpha_deg: float) -> float:
    return _linear_interpolate_clamped(
        alpha_deg,
        [x for x, _ in SCOUR_BETA_BY_ANGLE],
        [y for _, y in SCOUR_BETA_BY_ANGLE],
    )


def _sediment_e(params: dict[str, float]) -> float:
    if "S" not in params:
        return _positive(params, "E")
    sediment = _param(params, "S")
    if sediment < 1:
        return 0.46
    if sediment <= 10:
        return 0.66
    return 0.86


def calculate_scour(data: ScourCalculationInput) -> ScourCalculationResult:
    if data.method_key not in SCOUR_METHOD_MAP:
        raise HydrologyError(f"不支持的冲刷计算公式：{data.method_key}")
    method = SCOUR_METHOD_MAP[data.method_key]
    p = data.parameters
    details: list[tuple[str, str, str]] = []
    result_name = "冲刷深度"
    unit = "m"

    def add(name: str, value: float, note: str = "") -> float:
        details.append((name, f"{_safe_round(value, 6):g}", note))
        return value

    key = data.method_key
    if key == "slt_parallel_bank":
        hp = _positive(p, "hp")
        vp = _positive(p, "vp")
        vH = _positive(p, "vH")
        n = _positive(p, "n")
        value = max(0.0, hp * ((vp / vH) ** n - 1))
        add("vp/vH", vp / vH)
    elif key == "slt_oblique_bank":
        alpha_deg = _positive(p, "alpha_deg")
        alpha = math.radians(alpha_deg)
        vj_mode = int(round(_param(p, "vj_mode"))) if "vj_mode" in p else 0
        if vj_mode == 1:
            Q1 = _positive(p, "Q1")
            B1 = _positive(p, "B1")
            H1 = _positive(p, "H1")
            beta = add("β", _angle_beta(alpha_deg), "按表A.3.4-2线性插值")
            Vj = add("Vj", Q1 / (B1 * H1) * (2 * beta / (1 + beta)), "滩地河床，按A.3.4-3计算")
        elif vj_mode == 2:
            Q = _positive(p, "Q")
            W = _positive(p, "W")
            Wp = _param(p, "Wp")
            if W <= Wp:
                raise HydrologyError("W必须大于Wp")
            Vj = add("Vj", Q / (W - Wp), "无滩地河床，按A.3.4-4计算")
        else:
            Vj = _positive(p, "Vj")
            add("Vj", Vj, "手动输入")
        m = _positive(p, "m")
        d = _positive(p, "d")
        g = _positive(p, "g")
        value = max(0.0, 23 * math.tan(alpha / 2) * Vj * Vj / (math.sqrt(1 + m * m) * g) - 30 * d)
    elif key == "slt_wetland_vj":
        Q1 = _positive(p, "Q1")
        B1 = _positive(p, "B1")
        H1 = _positive(p, "H1")
        beta = add("β", _angle_beta(_positive(p, "alpha_deg")), "按表A.3.4-2线性插值")
        value = Q1 / (B1 * H1) * (2 * beta / (1 + beta))
        result_name = "局部冲刷流速Vj"
        unit = "m/s"
    elif key == "slt_no_floodplain_vj":
        Q = _positive(p, "Q")
        W = _positive(p, "W")
        Wp = _param(p, "Wp")
        if W <= Wp:
            raise HydrologyError("W必须大于Wp")
        value = Q / (W - Wp)
        result_name = "局部冲刷流速Vj"
        unit = "m/s"
    elif key == "slt_groyne_non_submerged":
        alpha_deg = _positive(p, "alpha_deg")
        tan_half = 1.0 if alpha_deg > 90 else math.tan(math.radians(alpha_deg) / 2)
        v = _positive(p, "v")
        l = _positive(p, "l")
        m = _positive(p, "m")
        d = _positive(p, "d")
        g = _positive(p, "g")
        K1 = add("K1", math.exp(-5.1 * math.sqrt(v * v / (g * l))))
        K2 = add("K2", math.exp(-0.2 * m))
        value = max(0.0, 27 * K1 * K2 * tan_half * v * v / g - 30 * d)
    elif key == "slt_groyne_fine_bed":
        h0 = _positive(p, "h0")
        v = _positive(p, "v")
        m = _positive(p, "m")
        alpha = math.radians(_positive(p, "alpha_deg"))
        value = h0 + 2.8 * v * v / math.sqrt(1 + m * m) * math.sin(alpha)
        result_name = "局部冲刷水深hB"
    elif key == "jtg_64_1_nonc_channel":
        Qc = _positive(p, "Qc")
        Bc = _positive(p, "Bc")
        E = add("E", _sediment_e(p), "按汛期含沙量S自动取值；若未输入S则使用手动E")
        dc = _positive(p, "dc")
        mu = _positive(p, "mu")
        hmc = _positive(p, "hmc")
        hc = _positive(p, "hc")
        Bd = _positive(p, "Bd")
        H = _positive(p, "H")
        A_raw = (math.sqrt(Bd) / H) ** 0.15
        A = add("A", min(A_raw, 1.8), "A=(sqrt(Bd)/H)^0.15；按规范说明控制A≤1.8")
        value = (A * (Qc / (mu * Bc)) * (hmc / hc) ** (5 / 3) / (E * dc ** (1 / 6))) ** (3 / 5)
        add("冲刷深度", max(0.0, value - hmc), "hp-hmc，仅用于成果复核")
        result_name = "桥下一般冲刷后最大水深hp"
    elif key == "jtg_64_2_nonc_simplified":
        Qp = _positive(p, "Qp")
        Qc = _positive(p, "Qc")
        Qt1 = _positive(p, "Qt1")
        Bc = _positive(p, "Bc")
        Bcg = _positive(p, "Bcg")
        blocked_ratio = _param(p, "lambda")
        if not 0 <= blocked_ratio < 1:
            raise HydrologyError("lambda必须在0至1之间，且不能等于1")
        mu = _positive(p, "mu")
        hcm = _positive(p, "hcm")
        Bz = _positive(p, "Bz")
        Hz = _positive(p, "Hz")
        Q2 = add("Q2", Qc / (Qc + Qt1) * Qp, "桥下河槽部分通过的设计流量")
        Ad_raw = (math.sqrt(Bz) / Hz) ** 0.15
        Ad = add("Ad", min(Ad_raw, 1.8), "Ad=(sqrt(Bz)/Hz)^0.15；按规范说明控制Ad≤1.8")
        width_ratio = add(
            "桥孔压缩比",
            Bc / ((1 - blocked_ratio) * mu * Bcg),
            "Bc/[(1-lambda)*mu*Bcg]",
        )
        value = 1.04 * (Ad * Q2 / Qc) ** 0.90 * width_ratio ** 0.66 * hcm
        add("冲刷深度", max(0.0, value - hcm), "hp-hcm，仅用于成果复核")
        result_name = "桥下一般冲刷后最大水深hp"
    elif key == "slt_bridge_nonc_floodplain":
        At = _positive(p, "At")
        Qt = _positive(p, "Qt")
        Bt = _positive(p, "Bt")
        hmt = _positive(p, "hmt")
        ht = _positive(p, "ht")
        VH1 = _positive(p, "VH1")
        value = (At * (Qt / Bt) * (hmt / ht) ** (5 / 3) / VH1) ** (5 / 6)
        add("冲刷深度", max(0.0, value - hmt), "hp-hmt，仅用于成果复核")
        result_name = "桥下河滩一般冲刷后最大水深hp"
    elif key == "slt_bridge_cohesive_channel":
        A = _positive(p, "A")
        Qc = _positive(p, "Qc")
        Bc = _positive(p, "Bc")
        hmc = _positive(p, "hmc")
        hc = _positive(p, "hc")
        IL = _positive(p, "IL")
        value = (A * (Qc / Bc) * (hmc / hc) ** (5 / 3) / (0.33 * (1 / IL))) ** (5 / 8)
        add("冲刷深度", max(0.0, value - hmc), "hp-hmc，仅用于成果复核")
        result_name = "桥下河槽一般冲刷后最大水深hp"
    elif key == "slt_bridge_cohesive_floodplain":
        Qt = _positive(p, "Qt")
        Bt = _positive(p, "Bt")
        hmt = _positive(p, "hmt")
        ht = _positive(p, "ht")
        IL = _positive(p, "IL")
        value = ((Qt / Bt) * (hmt / ht) ** (5 / 3) / (0.33 * (1 / IL))) ** (6 / 7)
        add("冲刷深度", max(0.0, value - hmt), "hp-hmt，仅用于成果复核")
        result_name = "桥下河滩一般冲刷后最大水深hp"
    elif key == "jtg_65_nonc_pier_auto":
        Kxi = _positive(p, "Kxi")
        B1 = _positive(p, "B1")
        v = _positive(p, "v")
        hp = _positive(p, "hp")
        d = _positive(p, "d")
        v0 = add("v0", 0.0246 * (hp / d) ** 0.14 * math.sqrt(332 * d + (10 + hp) / (d ** 0.72)), "河床泥沙启动流速")
        Keta = add("Kη", 0.8 * (1 / d ** 0.45 + 1 / d ** 0.15), "河床颗粒影响系数")
        v0p = add("v0'", 0.462 * (d / B1) ** 0.06 * v0, "墩前始冲流速")
        if v <= v0:
            value = max(0.0, Kxi * Keta * B1 ** 0.6 * (v - v0p))
            add("采用公式", 65.1, "v<=v0，采用65-1")
        else:
            n = add("n", (v0 / v) ** 0.25 * d ** -0.19)
            denom = max(v0 - v0p, 1e-9)
            value = max(0.0, Kxi * Keta * B1 ** 0.6 * (v - v0p) * ((v - v0p) / denom) ** n)
            add("采用公式", 65.2, "v>v0，采用65-2")
        result_name = "桥墩局部冲刷坑深hb"
    elif key == "jtg_65_2_nonc_pier_original":
        Kxi = _positive(p, "Kxi")
        B1 = _positive(p, "B1")
        v = _positive(p, "v")
        hp = _positive(p, "hp")
        d = _positive(p, "d")
        Keta2 = add("Kη2", 0.0023 / d ** 2.2 + 0.375 * d ** -0.24, "65-2原式河床颗粒影响系数")
        v0 = add("v0", 0.28 * math.sqrt(d + 0.7), "河床泥沙起动流速")
        v0p = add("v0'", 0.12 * (d + 0.5) ** 0.55, "墩前泥沙始冲流速")
        ratio = max(0.0, (v - v0p) / max(v0, 1e-9))
        if v <= v0:
            value = Kxi * Keta2 * B1 ** 0.6 * hp ** 0.15 * ratio
            add("采用公式", 65.2, "v<=v0，采用65-2第一分支")
        else:
            n2 = add("n2", (v0 / v) ** (0.23 + 0.19 * math.log10(d)))
            value = Kxi * Keta2 * B1 ** 0.6 * hp ** 0.15 * ratio ** n2
            add("采用公式", 65.2, "v>v0，采用65-2第二分支")
        result_name = "桥墩局部冲刷坑深hb"
    elif key == "slt_pier_cohesive_auto":
        Kxi = _positive(p, "Kxi")
        B1 = _positive(p, "B1")
        hp = _positive(p, "hp")
        IL = _positive(p, "IL")
        v = _positive(p, "v")
        ratio = add("hp/B1", hp / B1)
        if ratio >= 2.5:
            value = 0.83 * Kxi * B1 ** 0.6 * IL ** 1.25 * v
            add("采用公式", 3.513, "hp/B1>=2.5，采用A.3.5-13")
        else:
            value = 0.55 * Kxi * B1 ** 0.6 * hp ** 0.1 * IL * v
            add("采用公式", 3.514, "hp/B1<2.5，采用A.3.5-14")
        result_name = "桥墩局部冲刷坑深hb"
    else:
        raise HydrologyError(f"冲刷公式尚未实现：{key}")

    for param_key, desc, _default in method.parameters:
        if param_key in p:
            details.append((param_key, f"{_safe_round(p[param_key], 6):g}", desc))
    return ScourCalculationResult(
        method_key=method.key,
        method_name=method.name,
        category=method.category,
        source=method.source,
        formula=method.formula,
        result_name=result_name,
        result_value=_safe_round(value, 6),
        unit=unit,
        rows=tuple(details),
        note=method.note,
    )
