"""Serializa datos tabulares a formato CSV (RFC 4180)."""


def _escape_field(value: str, delimiter: str) -> str:
    """Escapa un campo segun RFC 4180 si contiene delimiter, comillas o newlines."""
    if any(c in value for c in (delimiter, '"', "\n", "\r")):
        return '"' + value.replace('"', '""') + '"'
    return value


def to_csv(
    rows: list[dict],
    columns: list[str] | None = None,
    delimiter: str = ",",
    include_header: bool = True,
) -> str:
    """Serializa datos tabulares a CSV.

    Implementacion manual sin csv module para control total del escaping.
    Cumple RFC 4180: escapa campos con comillas, newlines y delimiters.

    Args:
        rows: Lista de dicts con los datos. Todas las filas deben tener
              las mismas keys (o un subconjunto de columns).
        columns: Columnas a incluir y su orden. Si es None, usa las keys
                 de la primera fila en orden de insercion.
        delimiter: Separador de campos. Por defecto coma.
        include_header: Si True, incluye la fila de encabezados.

    Returns:
        String CSV completo. String vacio si rows es vacio.
    """
    if not rows:
        return ""

    cols = columns if columns is not None else list(rows[0].keys())

    output_lines: list[str] = []

    if include_header:
        output_lines.append(delimiter.join(_escape_field(c, delimiter) for c in cols))

    for row in rows:
        fields = []
        for col in cols:
            raw = row.get(col)
            if raw is None:
                fields.append("")
            else:
                fields.append(_escape_field(str(raw), delimiter))
        output_lines.append(delimiter.join(fields))

    return "\r\n".join(output_lines)
