from __future__ import annotations

import math
from decimal import Decimal
from typing import Any


class GeometricBreakdownEngine:
    """Động cơ giải toán hình học và sinh công thức phân rã chi tiết chuẩn Kỹ sư QS."""

    @staticmethod
    def calculate_pad_footing(
        length: float,
        width: float,
        base_height: float,
        taper_height: float = 0.0,
        top_length: float | None = None,
        top_width: float | None = None,
        count: int = 1,
        pile_count_per_footing: int = 0,
        pile_side_or_dia: float = 0.25,
        pile_embed_depth: float = 0.1,
    ) -> dict[str, Any]:
        """Tính thể tích bê tông móng đài cọc kèm trừ giao đầu cọc."""
        # 1. Thể tích khối đáy hộp chữ nhật
        v_base = length * width * base_height

        # 2. Thể tích phần chóp vát (nếu có)
        v_taper = 0.0
        if taper_height > 0:
            tl = top_length or (length * 0.5)
            tw = top_width or (width * 0.5)
            s1 = length * width
            s2 = tl * tw
            v_taper = (taper_height / 3.0) * (s1 + s2 + math.sqrt(s1 * s2))

        # 3. Thể tích trừ cọc cắm vào đài
        v_pile_deduct = 0.0
        if pile_count_per_footing > 0:
            v_one_pile = (pile_side_or_dia**2) * pile_embed_depth
            v_pile_deduct = v_one_pile * pile_count_per_footing

        v_one_footing = v_base + v_taper - v_pile_deduct
        v_total = v_one_footing * count

        # Diễn giải công thức toán học
        formula = f"{count} * ({length:.2f}*{width:.2f}*{base_height:.2f}"
        if taper_height > 0:
            formula += f" + chóp_vát({v_taper:.3f})"
        if pile_count_per_footing > 0:
            formula += f" - {pile_count_per_footing}*cọc({pile_side_or_dia:.2f}^2*{pile_embed_depth:.2f})"
        formula += f") = {v_total:.4f} m3"

        return {
            "task_name": "Bê tông móng đài cọc BTCT mác 250",
            "norm_code": "AF.11111",
            "unit": "m3",
            "quantity": Decimal(str(round(v_total, 4))),
            "formula_breakdown": formula,
        }

    @staticmethod
    def calculate_box_culvert(
        length: float,
        width_inner: float,
        height_inner: float,
        wall_thick: float = 0.2,
        bottom_thick: float = 0.25,
        top_thick: float = 0.2,
        count: int = 1,
    ) -> dict[str, Any]:
        """Tính thể tích bê tông cống hộp mương thoát nước."""
        width_outer = width_inner + (2 * wall_thick)
        height_outer = height_inner + bottom_thick + top_thick

        s_outer = width_outer * height_outer
        s_inner = width_inner * height_inner
        s_concrete = s_outer - s_inner

        v_total = s_concrete * length * count
        formula = f"{count} * [{length:.2f} * ({width_outer:.2f}*{height_outer:.2f} - {width_inner:.2f}*{height_inner:.2f})] = {v_total:.4f} m3"

        return {
            "task_name": "Bê tông cống hộp BTCT M250 đổ tại chỗ",
            "norm_code": "AF.12311",
            "unit": "m3",
            "quantity": Decimal(str(round(v_total, 4))),
            "formula_breakdown": formula,
        }

    @staticmethod
    def calculate_rebar_weight(
        bar_diameter_mm: float,
        total_length_m: float,
        hooks_count: int = 0,
        lap_count: int = 0,
    ) -> dict[str, Any]:
        """Tính trọng lượng cốt thép chuẩn TCVN."""
        hook_len = hooks_count * (6.25 * (bar_diameter_mm / 1000.0))
        lap_len = lap_count * (30 * (bar_diameter_mm / 1000.0))
        effective_length = total_length_m + hook_len + lap_len

        # Trọng lượng đơn vị: q = 0.006165 * d^2 (kg/m)
        unit_weight = 0.006165 * (bar_diameter_mm**2)
        weight_kg = effective_length * unit_weight
        weight_ton = weight_kg / 1000.0

        formula = f"({total_length_m:.2f}m + neo/nối {hook_len + lap_len:.2f}m) * {unit_weight:.3f} kg/m = {weight_kg:.2f} kg ({weight_ton:.4f} tấn)"

        code = (
            "AF.61111"
            if bar_diameter_mm <= 10
            else ("AF.61121" if bar_diameter_mm <= 18 else "AF.61131")
        )

        return {
            "task_name": f"Cốt thép phi {bar_diameter_mm:.0f} (<= {bar_diameter_mm:.0f}mm)",
            "norm_code": code,
            "unit": "tấn",
            "quantity": Decimal(str(round(weight_ton, 4))),
            "formula_breakdown": formula,
        }

    @staticmethod
    def calculate_trench_excavation(
        bottom_width: float,
        depth: float,
        length: float,
        slope_m: float = 0.5,
    ) -> dict[str, Any]:
        """Tính khối lượng đào đất hố móng / mương rãnh có mái taluy."""
        top_width = bottom_width + (2 * slope_m * depth)
        s_trap = ((bottom_width + top_width) / 2.0) * depth
        v_total = s_trap * length

        formula = f"{length:.2f} * [({bottom_width:.2f} + {top_width:.2f}) / 2 * {depth:.2f}] = {v_total:.4f} m3"

        return {
            "task_name": "Đào móng công trình đất cấp III bằng máy kết hợp thủ công",
            "norm_code": "AB.11311",
            "unit": "m3",
            "quantity": Decimal(str(round(v_total, 4))),
            "formula_breakdown": formula,
        }

    @staticmethod
    def calculate_revetment_pitching(
        crest_length: float,
        slope_height: float,
        slope_m: float = 1.5,
        stone_thickness: float = 0.30,
        gravel_filter_thick: float = 0.15,
        geotextile: bool = True,
    ) -> dict[str, Any]:
        """Tính khối lượng lát đá hộc bờ kè, tầng lọc cuội sỏi và trải vải địa kỹ thuật."""
        slope_length = math.sqrt(slope_height**2 + (slope_m * slope_height) ** 2)
        slope_area = crest_length * slope_length
        stone_vol = slope_area * stone_thickness
        gravel_vol = slope_area * gravel_filter_thick

        formula_stone = f"{crest_length:.2f}m dài * {slope_length:.2f}m sườn kè * {stone_thickness:.2f}m dày = {stone_vol:.4f} m3"
        formula_filter = f"{crest_length:.2f}m dài * {slope_length:.2f}m sườn kè * {gravel_filter_thick:.2f}m dày = {gravel_vol:.4f} m3"

        return {
            "task_name": "Kè đá hộc xây/lát khan bờ kênh gia cố chống xói lở",
            "norm_code": "AL.15110",
            "unit": "m3",
            "stone_volume_m3": Decimal(str(round(stone_vol, 4))),
            "gravel_filter_m3": Decimal(str(round(gravel_vol, 4))),
            "geotextile_area_m2": Decimal(str(round(slope_area * 1.10, 4)))
            if geotextile
            else Decimal(0),
            "formula_breakdown": formula_stone,
        }

    @staticmethod
    def calculate_formwork_area(
        contact_perimeter: float,
        height_or_length: float,
        count: int = 1,
        deduct_openings_area: float = 0.0,
    ) -> dict[str, Any]:
        """Tính diện tích ván khuôn tiếp xúc bê tông chuẩn xác."""
        gross_area = contact_perimeter * height_or_length * count
        net_area = max(0.0, gross_area - deduct_openings_area)

        formula = (
            f"{count} * ({contact_perimeter:.2f}m chu vi * {height_or_length:.2f}m cao)"
        )
        if deduct_openings_area > 0:
            formula += f" - {deduct_openings_area:.2f}m2 lỗ mở"
        formula += f" = {net_area:.4f} m2"

        return {
            "task_name": "Ván khuôn định hình thi công kết cấu bê tông",
            "norm_code": "AF.81110",
            "unit": "m2",
            "quantity": Decimal(str(round(net_area, 4))),
            "formula_breakdown": formula,
        }

    @staticmethod
    def calculate_pavement_slab(
        length: float,
        width: float,
        thickness: float = 0.20,
        joint_spacing_m: float = 5.0,
    ) -> dict[str, Any]:
        """Tính bê tông mặt đường/sân bãi, ván khuôn thành và chiều dài cắt khe co giãn."""
        area_m2 = length * width
        vol_m3 = area_m2 * thickness
        formwork_m2 = (2 * length + 2 * width) * thickness
        transverse_joints = max(0, int(length / joint_spacing_m))
        joint_length_m = transverse_joints * width + length  # Khe ngang + khe dọc

        formula = f"{length:.2f}m * {width:.2f}m * {thickness:.2f}m = {vol_m3:.4f} m3 ({area_m2:.2f} m2)"

        return {
            "task_name": "Bê tông mặt đường giao thông / sân bãi BTCT M250",
            "norm_code": "AF.15210",
            "unit": "m3",
            "concrete_volume_m3": Decimal(str(round(vol_m3, 4))),
            "surface_area_m2": Decimal(str(round(area_m2, 4))),
            "formwork_m2": Decimal(str(round(formwork_m2, 4))),
            "joint_length_m": Decimal(str(round(joint_length_m, 2))),
            "formula_breakdown": formula,
        }
