"""Convert a CSV file to Parquet format using DuckDB."""
from __future__ import annotations

from pathlib import Path


def csv_to_parquet_duckdb(
    csv_path: "str | Path",
    parquet_path: "str | Path",
    column_casts: "dict[str, str] | None" = None,
    overwrite: bool = False,
) -> bool:
    """Convert a CSV file to Parquet using DuckDB's read_csv_auto.

    If overwrite is False and the parquet file already exists, the function
    does nothing and returns False. Otherwise uses DuckDB to read the CSV
    (with automatic type inference) and writes it as Parquet.

    Optional column_casts allow overriding inferred types for specific columns
    (e.g. {"codigo_postal": "VARCHAR"} to prevent numeric coercion).

    Args:
        csv_path: Path to the source CSV file.
        parquet_path: Path for the output Parquet file.
        column_casts: Optional dict mapping column names to DuckDB SQL types.
        overwrite: If False (default), skip conversion when parquet exists.

    Returns:
        True if the Parquet file was written, False if skipped.

    Raises:
        FileNotFoundError: If csv_path does not exist.
        Exception: Any DuckDB error (malformed CSV, type cast failure, etc.).
    """
    import duckdb

    csv_p = Path(csv_path)
    parquet_p = Path(parquet_path)

    if not csv_p.exists():
        raise FileNotFoundError(f"CSV not found: {csv_p}")

    if not overwrite and parquet_p.exists():
        return False

    parquet_p.parent.mkdir(parents=True, exist_ok=True)

    con = duckdb.connect()
    try:
        if column_casts:
            cast_exprs = ", ".join(
                f"CAST({col} AS {dtype}) AS {col}"
                for col, dtype in column_casts.items()
            )
            # Build SELECT: cast specified columns, pass rest through
            # We do this via a subquery to get all columns first
            all_cols_query = f"DESCRIBE SELECT * FROM read_csv_auto('{csv_p}', header=true)"
            all_cols = [row[0] for row in con.execute(all_cols_query).fetchall()]
            select_parts = []
            for col in all_cols:
                if col in column_casts:
                    select_parts.append(f"CAST({col} AS {column_casts[col]}) AS {col}")
                else:
                    select_parts.append(col)
            select_expr = ", ".join(select_parts)
            sql = (
                f"COPY (SELECT {select_expr} FROM read_csv_auto('{csv_p}', header=true)) "
                f"TO '{parquet_p}' (FORMAT PARQUET)"
            )
        else:
            sql = (
                f"COPY (SELECT * FROM read_csv_auto('{csv_p}', header=true)) "
                f"TO '{parquet_p}' (FORMAT PARQUET)"
            )
        con.execute(sql)
    finally:
        con.close()

    return True
