from __future__ import annotations

from dataclasses import dataclass
from math import sqrt

from .core import HydrologyError


RIVER_EVOLUTION_METHODS = [
    "河相关系-格鲁什科夫宽深公式",
    "河相关系-量纲分析公式",
    "稳定河宽-阿尔图宁公式",
    "纵向稳定系数-希尔兹数倒数法",
    "纵向稳定系数-洛赫庆系数法",
    "横向稳定系数-方法一",
    "横向稳定系数-方法二",
    "综合稳定系数",
    "冲淤判别系数",
]


@dataclass(frozen=True)
class RiverEvolutionInput:
    method: str
    bankfull_width_b: float = 0.0
    average_depth_h: float = 0.0
    sediment_d: float = 0.0
    formative_flow_q: float = 0.0
    slope_j: float = 0.0
    stable_width_a: float = 1.0
    low_water_width_b: float = 0.0
    longitudinal_phi_h1: float = 0.0
    lateral_phi_b1: float = 0.0
    inlet_velocity_v0: float = 0.0
    outlet_velocity_vi: float = 0.0
    inlet_depth_h0: float = 0.0
    outlet_depth_hi: float = 0.0


@dataclass(frozen=True)
class RiverEvolutionResult:
    method: str
    formula: str
    value_name: str
    value: float
    unit: str
    judgement: str = ""
    note: str = ""


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


def classify_river_regime(zeta: float, dimensional: bool = False) -> str:
    if dimensional:
        if zeta < 16:
            return "接近蜿蜒型或较顺直过渡型下限"
        if zeta <= 20:
            return "较为顺直的过渡型河道"
        return "游荡型或宽浅摆动性较强河道"
    if zeta <= 4:
        return "蜿蜒型河道"
    if zeta <= 12:
        return "较为顺直的过渡型河道"
    if zeta <= 30:
        return "游荡型河道"
    return "宽浅游荡特征较强"


def classify_lateral_stability(phi_b: float) -> str:
    if 0.67 <= phi_b <= 0.77:
        return "蜿蜒型参考范围，横向相对稳定"
    if 0.17 <= phi_b <= 0.21:
        return "过渡型参考范围"
    if 0.07 <= phi_b <= 0.09:
        return "游荡型参考范围，横向稳定性较弱"
    if phi_b > 0.77:
        return "横向稳定性较强"
    if phi_b < 0.17:
        return "横向稳定性偏弱"
    return "介于常用河型参考范围之间，应结合实测断面复核"


def classify_erosion_deposition(psi: float) -> str:
    if psi < 0.95:
        return "冲刷趋势"
    if psi > 1.05:
        return "淤积趋势"
    return "冲淤基本平衡"


def calculate_river_evolution(data: RiverEvolutionInput) -> RiverEvolutionResult:
    method = data.method
    if method == "河相关系-格鲁什科夫宽深公式":
        b = _positive(data.bankfull_width_b, "平滩水面宽B")
        h = _positive(data.average_depth_h, "平均水深h")
        value = sqrt(b) / h
        return RiverEvolutionResult(method, "ζ = sqrt(B) / h", "河相系数ζ", value, "-", classify_river_regime(value))

    if method == "河相关系-量纲分析公式":
        b = _positive(data.bankfull_width_b, "平滩水面宽B")
        d = _positive(data.sediment_d, "床沙平均粒径d(mm)")
        h = _positive(data.average_depth_h, "平均水深h")
        value = sqrt(b * d) / h
        return RiverEvolutionResult(method, "ζ = sqrt(B*d) / h", "河相系数ζ", value, "-", classify_river_regime(value, dimensional=True))

    if method == "稳定河宽-阿尔图宁公式":
        q = _positive(data.formative_flow_q, "造床流量Q")
        j = _positive(data.slope_j, "河道综合比降J")
        a = _positive(data.stable_width_a, "稳定河宽系数A")
        value = a * sqrt(q) / (j ** 0.2)
        return RiverEvolutionResult(
            method,
            "B = A * Q^0.5 / J^0.2",
            "稳定河宽B",
            value,
            "m",
            note="J按小数输入，例如1.11‰输入0.00111；A按河段类型选取：山区0.75~0.90，山麓0.90~1.00，中游1.00~1.10，下游1.10~1.70。",
        )

    if method == "纵向稳定系数-希尔兹数倒数法":
        d = _positive(data.sediment_d, "床沙平均粒径d(mm)")
        h = _positive(data.average_depth_h, "平均水深h")
        j = _positive(data.slope_j, "比降J(小数)")
        value = d / (h * j)
        return RiverEvolutionResult(method, "φh1 = d / (h*J)", "纵向稳定系数φh1", value, "-", note="d按mm输入，J按小数输入；1‰填0.001。")

    if method == "纵向稳定系数-洛赫庆系数法":
        d = _positive(data.sediment_d, "床沙平均粒径d(mm)")
        j = _positive(data.slope_j, "比降J(小数)")
        value = d / j
        return RiverEvolutionResult(method, "φh2 = d / J", "纵向稳定系数φh2", value, "-", note="d按mm输入，J按小数输入；1‰填0.001。")

    if method == "横向稳定系数-方法一":
        q = _positive(data.formative_flow_q, "平滩流量Q")
        j = _positive(data.slope_j, "纵比降J(小数)")
        b = _positive(data.bankfull_width_b, "平滩河宽B")
        value = sqrt(q) / ((j ** 0.2) * b)
        return RiverEvolutionResult(method, "φb1 = Q^0.5 / (J^0.2 * B)", "横向稳定系数φb1", value, "-", classify_lateral_stability(value))

    if method == "横向稳定系数-方法二":
        low_b = _positive(data.low_water_width_b, "枯水河宽b")
        b = _positive(data.bankfull_width_b, "平滩河宽B")
        value = low_b / b
        return RiverEvolutionResult(method, "φb2 = b / B", "横向稳定系数φb2", value, "-", classify_lateral_stability(value))

    if method == "综合稳定系数":
        phi_h1 = _positive(data.longitudinal_phi_h1, "纵向稳定系数φh₁")
        phi_b1 = _positive(data.lateral_phi_b1, "横向稳定系数φb₁")
        value = phi_h1 * (phi_b1 ** 2)
        return RiverEvolutionResult(method, "φ = φh1 * (φb1)^2", "综合稳定系数φ", value, "-", "综合稳定性指标")

    if method == "冲淤判别系数":
        v0 = _positive(data.inlet_velocity_v0, "进口断面流速v₀")
        vi = _positive(data.outlet_velocity_vi, "出口断面流速vᵢ")
        h0 = _positive(data.inlet_depth_h0, "进口断面水深h₀")
        hi = _positive(data.outlet_depth_hi, "出口断面水深hᵢ")
        value = (v0 ** 1.5 * hi) / (vi ** 1.5 * h0)
        return RiverEvolutionResult(method, "ψ = (v₀^(3/2)·hᵢ) / (vᵢ^(3/2)·h₀)", "冲淤判别系数ψ", value, "-", classify_erosion_deposition(value))

    raise HydrologyError(f"未知河道演变计算方法：{method}")
