from __future__ import annotations

from dataclasses import dataclass
from math import pow

from .core import HydrologyError


RIVER_SEGMENT_PARAMS = {
    "开阔、顺直微弯河段": {"Kq": 0.84, "n3": 0.90},
    "分汊、弯曲河段": {"Kq": 0.95, "n3": 0.87},
    "滩、槽可分的不稳定河段": {"Kq": 0.69, "n3": 1.59},
}

BRIDGE_OPENING_METHODS = [
    "峡谷河段",
    "开阔、顺直微弯河段",
    "分汊、弯曲河段",
    "滩、槽可分的不稳定河段",
    "宽滩河段",
    "滩、槽难分的不稳定河段",
]


@dataclass(frozen=True)
class BridgeOpeningInput:
    method: str
    design_flow_qp: float = 0.0
    channel_flow_qc: float = 0.0
    channel_width_bc: float = 0.0
    average_unit_discharge_qc: float = 0.0
    floodplain_flow_qt: float = 0.0
    annual_mean_max_flow_qbar: float = 0.0
    bed_sediment_dbar: float = 0.0
    flood_flow_q2_percent: float = 0.0


@dataclass(frozen=True)
class BridgeOpeningResult:
    method: str
    formula: str
    min_clear_length_lj: float | None
    beta: float | None = None
    basic_width_b0: float | None = None
    frequency_factor_cp: float | None = None
    kq: float | None = None
    n3: float | None = None
    note: str = ""


def _positive(value: float, name: str) -> float:
    if value <= 0:
        raise HydrologyError(f"{name} 必须大于0")
    return value


def calculate_bridge_opening(data: BridgeOpeningInput) -> BridgeOpeningResult:
    method = data.method
    if method == "峡谷河段":
        return BridgeOpeningResult(
            method=method,
            formula="峡谷河段可按河床地形布孔，不宜压缩河槽，可不作桥孔最小净长度计算。",
            min_clear_length_lj=None,
            note="请结合设计洪水位、两岸地形、路线条件和通航/漂浮物通过要求确定桥孔布设。",
        )

    if method in RIVER_SEGMENT_PARAMS:
        qp = _positive(data.design_flow_qp, "设计流量Qₚ")
        qc = _positive(data.channel_flow_qc, "河槽流量Qc")
        bc = _positive(data.channel_width_bc, "河槽宽度Bc")
        params = RIVER_SEGMENT_PARAMS[method]
        kq = params["Kq"]
        n3 = params["n3"]
        lj = kq * pow(qp / qc, n3) * bc
        return BridgeOpeningResult(
            method=method,
            formula="Lj = Kq * (Qₚ / Qc)^n₃ * Bc",
            min_clear_length_lj=lj,
            kq=kq,
            n3=n3,
            note="适用于开阔、顺直微弯、分汊、弯曲及滩槽可分不稳定河段；Kq、n₃按表7.2.1取值。",
        )

    if method == "宽滩河段":
        qp = _positive(data.design_flow_qp, "设计流量Qₚ")
        qc = _positive(data.channel_flow_qc, "河槽流量Qc")
        qt = _positive(data.floodplain_flow_qt, "河滩流量Qt")
        unit_q = _positive(data.average_unit_discharge_qc, "河槽平均单宽流量qc")
        beta = 1.19 * pow(qc / qt, 0.10)
        lj = qp / (beta * unit_q)
        return BridgeOpeningResult(
            method=method,
            formula="Lj = Qₚ / (β * qc)，β = 1.19 * (Qc / Qt)^0.10",
            min_clear_length_lj=lj,
            beta=beta,
            note="适用于宽滩河段。qc为河槽平均单宽流量，Qt为河滩流量。",
        )

    if method == "滩、槽难分的不稳定河段":
        qp = _positive(data.design_flow_qp, "设计流量Qₚ")
        qbar = _positive(data.annual_mean_max_flow_qbar, "年最大流量平均值Q̄")
        dbar = _positive(data.bed_sediment_dbar, "河床泥沙平均粒径d̄")
        q2 = _positive(data.flood_flow_q2_percent, "频率2%洪水流量Q₂%")
        b0 = 16.07 * pow(qbar / pow(dbar, 0.3), 0.24)
        cp = pow(qp / q2, 0.33)
        lj = cp * b0
        return BridgeOpeningResult(
            method=method,
            formula="Lj = Cp * B₀，B₀ = 16.07 * (Q̄ / d̄^0.3)^0.24，Cp = (Qₚ / Q₂%)^0.33",
            min_clear_length_lj=lj,
            basic_width_b0=b0,
            frequency_factor_cp=cp,
            note=(
                "适用于滩、槽难分的不稳定河段；河床泥沙平均粒径d̄按JTG C30-2015式(7.2.1-4)以m输入。"
                "计算值是桥孔最小净长度初值，最终桥长还需结合地形、壅水、冲刷、桥型及漂浮物要求确定。"
            ),
        )

    raise HydrologyError(f"未知桥孔计算河段类型：{method}")
