"""Tests para upsert_xlsx_sheet."""

import os
import sys

from openpyxl import Workbook, load_workbook

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

from functions.infra.upsert_xlsx_sheet import upsert_xlsx_sheet


def _build_initial_book(path):
    """Crea un libro con dos hojas: 'Datos' (gestionada con valor manual) y
    'Personal' (trabajo del usuario que NO debe tocarse).
    """
    wb = Workbook()
    wb.remove(wb.active)

    datos = wb.create_sheet("Datos")
    # Cabecera de la hoja gestionada.
    for c, name in enumerate(["Programa", "Clicks", "Ingreso", "EPC"], start=1):
        datos.cell(row=1, column=c, value=name)
    # Fila existente para Alpha con un valor manual en "Ingreso".
    datos.cell(row=2, column=1, value="Alpha")
    datos.cell(row=2, column=2, value=10)
    datos.cell(row=2, column=3, value=999)  # valor manual a preservar

    personal = wb.create_sheet("Personal")
    personal.cell(row=1, column=1, value="mis_notas")
    personal.cell(row=2, column=1, value="no me toques")
    personal.cell(row=2, column=2, value=1234)

    wb.save(path)


def test_no_destructivo_y_preserva_trabajo_manual(tmp_path):
    path = str(tmp_path / "libro.xlsx")
    _build_initial_book(path)

    result = upsert_xlsx_sheet(
        xlsx_path=path,
        sheet_name="Datos",
        records=[
            {"Programa": "Alpha", "Clicks": 100, "Ingreso": 50},
            {"Programa": "Beta", "Clicks": 200, "Ingreso": 80},
            {"Programa": "Gamma", "Clicks": 300, "Ingreso": 120},
        ],
        columns=["Programa", "Clicks", "Ingreso", "EPC"],
        key_col="Programa",
        preserve_cols=["Ingreso"],
        formulas={"EPC": {"f": '=IFERROR({Ingreso}{row}/{Clicks}{row},"")', "fmt": "0.00"}},
    )

    # El dict de retorno reporta lo esperado.
    assert result["sheet"] == "Datos"
    assert result["rows_written"] == 3
    assert "Personal" in result["other_sheets_preserved"]
    assert result["manual_cells_preserved"] == 1
    assert result["backup_path"] == path + ".bak"

    wb = load_workbook(path)

    # (a) La hoja "Personal" sigue existiendo con sus valores intactos.
    assert "Personal" in wb.sheetnames
    personal = wb["Personal"]
    assert personal.cell(row=1, column=1).value == "mis_notas"
    assert personal.cell(row=2, column=1).value == "no me toques"
    assert personal.cell(row=2, column=2).value == 1234

    datos = wb["Datos"]
    header = {datos.cell(row=1, column=c).value: c for c in range(1, datos.max_column + 1)}

    # Localizar la fila de Alpha por la columna clave.
    alpha_row = None
    for r in range(2, datos.max_row + 1):
        if datos.cell(row=r, column=header["Programa"]).value == "Alpha":
            alpha_row = r
            break
    assert alpha_row is not None

    # (b) El valor manual en "Ingreso" para Alpha (999) NO se pisó con 50.
    assert datos.cell(row=alpha_row, column=header["Ingreso"]).value == 999

    # (c) Se añadieron las filas nuevas (Beta y Gamma no existían antes).
    programas = {
        datos.cell(row=r, column=header["Programa"]).value
        for r in range(2, datos.max_row + 1)
    }
    assert {"Alpha", "Beta", "Gamma"} <= programas

    # (d) La columna de fórmula contiene una fórmula.
    epc = datos.cell(row=alpha_row, column=header["EPC"]).value
    assert isinstance(epc, str) and epc.startswith("=")
    assert "IFERROR" in epc


def test_crea_libro_nuevo_si_no_existe(tmp_path):
    path = str(tmp_path / "nuevo.xlsx")
    assert not os.path.exists(path)

    result = upsert_xlsx_sheet(
        xlsx_path=path,
        sheet_name="Hoja1",
        records=[{"A": "x", "B": "y"}],
        columns=["A", "B"],
    )

    assert os.path.exists(path)
    # Sin archivo previo no hay backup.
    assert result["backup_path"] == ""
    assert result["rows_written"] == 1

    wb = load_workbook(path)
    assert wb.sheetnames == ["Hoja1"]
    ws = wb["Hoja1"]
    assert ws.cell(row=1, column=1).value == "A"
    assert ws.cell(row=2, column=1).value == "x"
