"""Tests para load_bq_table_to_duckdb.

Cubre la lógica PURA extraíble sin red ni BigQuery: la construcción del SELECT
sobre el origen (`_build_source_sql` — combinación de where_sql + sample_frac con
AND, select_sql sustituyendo a `*`, límite duro) y el saneado del nombre de tabla
destino (`_sanitize_dest_table`). No se toca la red: importar el módulo solo carga
`hashlib`/`re` a nivel superior (BigQuery/DuckDB/pyarrow se importan dentro de la
función impura, que aquí no se invoca).
"""

import os
import sys

sys.path.insert(0, os.path.dirname(__file__))

from load_bq_table_to_duckdb import _build_source_sql, _sanitize_dest_table

_FQN = "autingo-159109.data.ventas"


# --------------------------------------------------------------------------- #
# _build_source_sql — golden / defaults
# --------------------------------------------------------------------------- #
def test_default_selects_star_no_where_no_limit():
    sql = _build_source_sql(_FQN)
    assert sql == "SELECT * FROM `autingo-159109.data.ventas`"


def test_select_sql_replaces_star():
    sql = _build_source_sql(
        _FQN,
        select_sql="fecha, idCentro, CAST(venta_n AS FLOAT64) AS venta_n",
    )
    assert sql == (
        "SELECT fecha, idCentro, CAST(venta_n AS FLOAT64) AS venta_n "
        "FROM `autingo-159109.data.ventas`"
    )


def test_select_sql_blank_and_whitespace_fall_back_to_star():
    assert _build_source_sql(_FQN, select_sql="").startswith("SELECT * FROM")
    assert _build_source_sql(_FQN, select_sql="   ").startswith("SELECT * FROM")


# --------------------------------------------------------------------------- #
# where_sql y sample_frac — solos y combinados con AND
# --------------------------------------------------------------------------- #
def test_where_sql_only():
    sql = _build_source_sql(_FQN, where_sql="fecha <= CURRENT_DATE()")
    assert sql == (
        "SELECT * FROM `autingo-159109.data.ventas` "
        "WHERE fecha <= CURRENT_DATE()"
    )


def test_sample_frac_only():
    sql = _build_source_sql(_FQN, sample_frac=0.05)
    assert sql == "SELECT * FROM `autingo-159109.data.ventas` WHERE rand() < 0.05"


def test_where_sql_and_sample_frac_combined_with_and_parenthesized():
    sql = _build_source_sql(
        _FQN,
        where_sql="fecha <= CURRENT_DATE() AND venta_n IS NOT NULL",
        sample_frac=0.1,
    )
    # Dos condiciones -> cada una entre paréntesis, unidas con AND.
    assert sql == (
        "SELECT * FROM `autingo-159109.data.ventas` "
        "WHERE (fecha <= CURRENT_DATE() AND venta_n IS NOT NULL) "
        "AND (rand() < 0.1)"
    )


def test_single_condition_not_parenthesized():
    # Con una sola condición no se envuelve en paréntesis (más limpio).
    assert " WHERE fecha = 1" in _build_source_sql(_FQN, where_sql="fecha = 1")


# --------------------------------------------------------------------------- #
# max_rows (LIMIT) — solo y combinado
# --------------------------------------------------------------------------- #
def test_max_rows_appends_limit():
    sql = _build_source_sql(_FQN, max_rows=1000)
    assert sql == "SELECT * FROM `autingo-159109.data.ventas` LIMIT 1000"


def test_max_rows_zero_or_negative_no_limit():
    assert "LIMIT" not in _build_source_sql(_FQN, max_rows=0)
    assert "LIMIT" not in _build_source_sql(_FQN, max_rows=-5)


def test_all_combined_order_where_then_limit():
    sql = _build_source_sql(
        _FQN,
        select_sql="a, b",
        where_sql="a > 0",
        sample_frac=0.2,
        max_rows=500,
    )
    assert sql == (
        "SELECT a, b FROM `autingo-159109.data.ventas` "
        "WHERE (a > 0) AND (rand() < 0.2) LIMIT 500"
    )


# --------------------------------------------------------------------------- #
# sample_frac fuera de rango -> no muestrea
# --------------------------------------------------------------------------- #
def test_sample_frac_out_of_range_ignored():
    # >=1, <=0 y None no añaden la cláusula rand().
    assert "rand()" not in _build_source_sql(_FQN, sample_frac=1.0)
    assert "rand()" not in _build_source_sql(_FQN, sample_frac=0.0)
    assert "rand()" not in _build_source_sql(_FQN, sample_frac=None)


# --------------------------------------------------------------------------- #
# _sanitize_dest_table
# --------------------------------------------------------------------------- #
def test_dest_empty_uses_last_fqn_segment():
    assert _sanitize_dest_table("", "proj.dataset.customer_profile") == "customer_profile"


def test_dest_explicit_valid_kept():
    assert _sanitize_dest_table("mi_tabla", _FQN) == "mi_tabla"


def test_dest_invalid_chars_replaced_with_underscore():
    assert _sanitize_dest_table("my-table", _FQN) == "my_table"
    assert _sanitize_dest_table("weird!!name", _FQN) == "weird__name"


def test_dest_from_fqn_segment_with_hyphen_sanitized():
    # El último segmento con guiones se sanea (guion no es válido en identificador).
    assert _sanitize_dest_table("", "proj.dataset.tabla-con-guiones") == "tabla_con_guiones"
