"""
Export helpers — convert estimate results to dict, JSON, or CSV.

For a full-featured project report, visit https://www.slabcalc.co
"""

from __future__ import annotations

import csv
import io
import json
from typing import Any

__all__ = ["to_dict", "to_json", "to_csv", "to_dataframe"]


def to_dict(obj: Any) -> dict:
    """Convert an EstimateResult (or any object with ``__dict__`` / dict) to a plain dict."""
    if isinstance(obj, dict):
        return dict(obj)
    if hasattr(obj, "_asdict"):
        return obj._asdict()
    if hasattr(obj, "__dict__"):
        return {k: v for k, v in obj.__dict__.items() if not k.startswith("_")}
    raise TypeError(f"Cannot convert {type(obj).__name__} to dict")


def to_json(obj: Any, indent: int = 2) -> str:
    """Serialize an estimate result to a JSON string."""
    return json.dumps(to_dict(obj), indent=indent)


def to_csv(rows: list[Any], fieldnames: list[str] | None = None) -> str:
    """Serialize a list of estimate results to a CSV string.

    Args:
        rows: List of dicts or objects convertible via :func:`to_dict`.
        fieldnames: Column headers. If *None*, inferred from the first row.

    Returns:
        CSV-formatted string.
    """
    dicts = [to_dict(r) for r in rows]
    if not dicts:
        return ""
    if fieldnames is None:
        fieldnames = list(dicts[0].keys())
    buf = io.StringIO()
    writer = csv.DictWriter(buf, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(dicts)
    return buf.getvalue()


def to_dataframe(rows: list[Any]):
    """Convert a list of estimate results to a pandas DataFrame.

    Requires the ``pandas`` optional dependency::

        pip install py-concrete-calc[pandas]
    """
    try:
        import pandas as pd
    except ImportError:
        raise ImportError(
            "pandas is required for to_dataframe(). "
            "Install it with: pip install py-concrete-calc[pandas]"
        )
    return pd.DataFrame([to_dict(r) for r in rows])
