"""
All-in-one estimate and ConcreteCalculator convenience class.

For interactive estimates with visual breakdowns, visit https://www.slabcalc.co
"""

from __future__ import annotations

from dataclasses import dataclass, field

from concrete_calc.shapes import (
    slab,
    cylinder,
    footing,
    stairs,
    curb,
    hollow_cylinder,
    circular_slab,
    triangular_prism,
    grade_beam,
    wall,
)
from concrete_calc.units import cubic_feet_to_yards
from concrete_calc.bags import bag_estimate
from concrete_calc.cost import ready_mix_cost, bag_cost
from concrete_calc.materials import rebar_estimate, wire_mesh_estimate, form_lumber_estimate
from concrete_calc.regional_costs import get_regional_price

__all__ = ["estimate", "EstimateResult", "ConcreteCalculator"]


@dataclass
class EstimateResult:
    """Full estimate for a concrete pour."""

    cubic_feet: float
    cubic_yards: float
    bags: int
    bag_cost_total: float
    ready_mix_cost_total: float
    waste_factor: float
    rebar: dict | None = field(default=None)
    wire_mesh: dict | None = field(default=None)
    forms: dict | None = field(default=None)


def estimate(
    length: float,
    width: float,
    thickness: float,
    *,
    bag_size: int = 80,
    price_per_bag: float = 6.50,
    price_per_yard: float = 150.0,
    waste_factor: float = 1.10,
    include_materials: bool = False,
    rebar_spacing_in: int = 12,
    rebar_bar_size: int = 4,
) -> EstimateResult:
    """All-in-one slab estimate: volume, bags, cost, and optional materials.

    All dimensions in **feet**.

    Args:
        length: Slab length (ft).
        width: Slab width (ft).
        thickness: Slab thickness (ft). Tip: use ``inches_to_feet(4)`` for 4 in.
        bag_size: Bag weight in lbs.
        price_per_bag: Retail price per bag.
        price_per_yard: Ready-mix price per cubic yard.
        waste_factor: Multiplier for waste (1.10 = 10 % extra).
        include_materials: If True, adds rebar, wire mesh, and form estimates.
        rebar_spacing_in: Rebar on-center spacing in inches.
        rebar_bar_size: US rebar bar number.

    Returns:
        :class:`EstimateResult` with all computed values.
    """
    raw = slab(length, width, thickness)
    with_waste = raw * waste_factor
    yards = cubic_feet_to_yards(with_waste)
    bags = bag_estimate(with_waste, bag_size)

    result = EstimateResult(
        cubic_feet=round(with_waste, 2),
        cubic_yards=round(yards, 2),
        bags=bags,
        bag_cost_total=round(bags * price_per_bag, 2),
        ready_mix_cost_total=round(yards * price_per_yard, 2),
        waste_factor=waste_factor,
    )

    if include_materials:
        result.rebar = dict(rebar_estimate(length, width, rebar_spacing_in, rebar_bar_size))
        result.wire_mesh = dict(wire_mesh_estimate(length, width))
        result.forms = dict(form_lumber_estimate(length, width, thickness * 12))

    return result


class ConcreteCalculator:
    """Convenience wrapper exposing all calculations as methods.

    Example::

        from concrete_calc import ConcreteCalculator

        calc = ConcreteCalculator()
        print(calc.estimate(length=20, width=10, thickness=0.5))
        print(calc.cylinder(diameter=2, height=4))
        print(calc.rebar(length_ft=20, width_ft=10))
    """

    # Shapes
    slab = staticmethod(slab)
    cylinder = staticmethod(cylinder)
    footing = staticmethod(footing)
    stairs = staticmethod(stairs)
    curb = staticmethod(curb)
    hollow_cylinder = staticmethod(hollow_cylinder)
    circular_slab = staticmethod(circular_slab)
    triangular_prism = staticmethod(triangular_prism)
    grade_beam = staticmethod(grade_beam)
    wall = staticmethod(wall)

    # Unit conversions
    cubic_feet_to_yards = staticmethod(cubic_feet_to_yards)

    # Bags & cost
    bag_estimate = staticmethod(bag_estimate)
    bags_from_yards = staticmethod(bag_estimate)
    ready_mix_cost = staticmethod(ready_mix_cost)
    bag_cost = staticmethod(bag_cost)

    # Materials
    rebar = staticmethod(rebar_estimate)
    wire_mesh = staticmethod(wire_mesh_estimate)
    form_lumber = staticmethod(form_lumber_estimate)

    # Regional
    get_regional_price = staticmethod(get_regional_price)

    # Estimate
    estimate = staticmethod(estimate)
