"""Tests para extract_timeseries_raw.

No usa DuckDB real: inyecta un query_fn FAKE (closure) que devuelve filas
predefinidas y, opcionalmente, captura el SQL recibido para verificar la query
generada (ORDER BY por la columna temporal + LIMIT). Asi el test es
autocontenido y no depende de ningun backend.
"""

import os
import sys

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

from extract_timeseries_raw import extract_timeseries_raw


def _fake_query(rows, captured=None, status="ok", error=None):
    """Crea un query_fn FAKE.

    `captured` (lista opcional) recibe el SQL ejecutado para poder inspeccionarlo.
    `status`/`error` permiten simular un fallo del backend.
    """

    def _q(sql):
        if captured is not None:
            captured.append(sql)
        if status != "ok":
            return {"status": "error", "error": error or "boom"}
        return {"status": "ok", "rows": rows}

    return _q


def test_golden_t_y_series_alineadas():
    """Golden: t y series alineadas, floats convertidos, n correcto."""
    rows = [
        {"fecha": "2024-01-01", "ventas": "10", "stock": 5},
        {"fecha": "2024-01-02", "ventas": "20.5", "stock": 7},
        {"fecha": "2024-01-03", "ventas": 30, "stock": 9},
    ]
    res = extract_timeseries_raw(_fake_query(rows), "t", "fecha", ["ventas", "stock"])
    assert res["status"] == "ok"
    assert res["n"] == 3
    assert res["time_col"] == "fecha"
    assert res["t"] == ["2024-01-01", "2024-01-02", "2024-01-03"]
    assert res["series"]["ventas"] == [10.0, 20.5, 30.0]
    assert res["series"]["stock"] == [5.0, 7.0, 9.0]


def test_valor_no_convertible_da_none():
    """Valor no convertible a float -> None en la serie (alineacion preservada)."""
    rows = [
        {"fecha": "2024-01-01", "ventas": "abc"},
        {"fecha": "2024-01-02", "ventas": None},
        {"fecha": "2024-01-03", "ventas": "12.5"},
    ]
    res = extract_timeseries_raw(_fake_query(rows), "t", "fecha", ["ventas"])
    assert res["status"] == "ok"
    assert res["series"]["ventas"] == [None, None, 12.5]
    assert res["n"] == 3


def test_value_cols_vacia_status_error():
    """value_cols vacia -> status error con t/series/n vacios."""
    res = extract_timeseries_raw(_fake_query([]), "t", "fecha", [])
    assert res["status"] == "error"
    assert "value_cols" in res["error"]
    assert res["t"] == []
    assert res["series"] == {}
    assert res["n"] == 0


def test_query_fn_status_error_propaga():
    """query_fn que devuelve status != ok -> se propaga como error."""
    res = extract_timeseries_raw(
        _fake_query([], status="error", error="db locked"),
        "t",
        "fecha",
        ["ventas"],
    )
    assert res["status"] == "error"
    assert "db locked" in res["error"]
    assert res["n"] == 0


def test_query_fn_none_da_error_sin_reventar():
    """query_fn None -> error degradado, sin excepcion."""
    res = extract_timeseries_raw(None, "t", "fecha", ["ventas"])
    assert res["status"] == "error"
    assert res["t"] == []
    assert res["n"] == 0


def test_sql_contiene_order_by_y_limit():
    """La query generada ordena por time_col y aplica el LIMIT sobre la tabla."""
    captured = []
    rows = [{"fecha": "2024-01-01", "ventas": 1}]
    extract_timeseries_raw(
        _fake_query(rows, captured),
        "ventas_tbl",
        "fecha",
        ["ventas"],
        max_rows=123,
    )
    assert len(captured) == 1
    sql = captured[0]
    assert 'ORDER BY "fecha"' in sql
    assert "LIMIT 123" in sql
    assert 'FROM "ventas_tbl"' in sql
