import pandas as pd
import pytest

from mnemosynecore import reporting


def test_send_query_report(monkeypatch):
    df = pd.DataFrame([{"x": 1, "y": 2}])
    captured = {"preview": 0, "csv": 0}

    monkeypatch.setattr(reporting, "vertica_select", lambda **kwargs: df)
    monkeypatch.setattr(
        reporting,
        "post_message",
        lambda **kwargs: {"post_id": "P1", "root_id": kwargs.get("root_id")},
    )
    monkeypatch.setattr(
        reporting,
        "send_dataframe_preview",
        lambda **kwargs: captured.__setitem__("preview", captured["preview"] + 1),
    )
    monkeypatch.setattr(
        reporting,
        "send_dataframe_as_csv",
        lambda **kwargs: captured.__setitem__("csv", captured["csv"] + 1) or {"file_id": "F1"},
    )

    out = reporting.send_query_report(
        channel_id="CH",
        bot_id="BOT",
        conn_id="VERT",
        sql="select 1",
        header_text="header",
    )

    assert out["rows"] == 1
    assert out["header_post_id"] == "P1"
    assert captured["preview"] == 1
    assert captured["csv"] == 1


def test_send_kpi_report(monkeypatch):
    current_df = pd.DataFrame([{"metric": "revenue", "value": 120}, {"metric": "orders", "value": 40}])
    previous_df = pd.DataFrame([{"metric": "revenue", "value": 100}, {"metric": "orders", "value": 50}])
    calls = {"i": 0}

    def fake_select(**kwargs):
        calls["i"] += 1
        return current_df if calls["i"] == 1 else previous_df

    monkeypatch.setattr(reporting, "vertica_select", fake_select)
    monkeypatch.setattr(
        reporting,
        "post_message",
        lambda **kwargs: {"post_id": "KPI1", "root_id": kwargs.get("root_id")},
    )
    monkeypatch.setattr(reporting, "send_dataframe_preview", lambda **kwargs: None)
    monkeypatch.setattr(reporting, "send_dataframe_as_csv", lambda **kwargs: {"file_id": "F1"})

    out = reporting.send_kpi_report(
        channel_id="CH",
        bot_id="BOT",
        conn_id="VERT",
        current_sql="current",
        previous_sql="previous",
    )
    result_df = out["dataframe"]
    assert set(result_df.columns) >= {"metric", "current", "previous", "delta_abs", "delta_pct"}
    assert float(result_df.loc[result_df["metric"] == "revenue", "delta_abs"].iloc[0]) == 20.0


def test_data_quality_report_and_format():
    df = pd.DataFrame(
        [
            {"a": 1, "b": 10, "dt": "2026-01-01"},
            {"a": None, "b": 11, "dt": "2026-01-02"},
            {"a": None, "b": 1000, "dt": "2026-01-03"},
            {"a": None, "b": 1000, "dt": "2026-01-03"},
        ]
    )
    report = reporting.data_quality_report(df=df, freshness_col="dt", top_n=2)
    text = reporting.format_data_quality_report(report, title="DQ")

    assert report["rows"] == 4
    assert report["duplicate_count"] == 1
    assert "rows=4" in text
    assert "duplicates=1" in text


def test_send_data_quality_report(monkeypatch):
    df = pd.DataFrame([{"a": 1}, {"a": None}])
    preview_calls = {"n": 0}

    monkeypatch.setattr(
        reporting,
        "post_message",
        lambda **kwargs: {"post_id": "DQ1", "root_id": kwargs.get("root_id")},
    )
    monkeypatch.setattr(
        reporting,
        "send_dataframe_preview",
        lambda **kwargs: preview_calls.__setitem__("n", preview_calls["n"] + 1),
    )

    out = reporting.send_data_quality_report(
        channel_id="CH",
        bot_id="BOT",
        df=df,
        include_details=True,
    )
    assert out["post"]["post_id"] == "DQ1"
    assert preview_calls["n"] == 2


def test_sharepoint_to_vertica_upsert(monkeypatch):
    df = pd.DataFrame([{"id": 1, "value": 10}])
    captured = {}

    monkeypatch.setattr(reporting, "sharepoint_read_dataframe", lambda **kwargs: df)
    monkeypatch.setattr(reporting, "vertica_upsert", lambda **kwargs: captured.update(kwargs))

    out = reporting.sharepoint_to_vertica(
        sharepoint_conn="SP",
        file_url="/x.csv",
        table_name="mart.tbl",
        vertica_conn_id="VERT",
        mode="upsert",
        unique_keys=["id"],
    )
    assert out["rows"] == 1
    assert captured["table_name"] == "mart.tbl"


def test_sharepoint_to_vertica_insert(monkeypatch):
    df = pd.DataFrame([{"id": 1, "value": 10}])
    captured = {}

    monkeypatch.setattr(reporting, "sharepoint_read_dataframe", lambda **kwargs: df)
    monkeypatch.setattr(reporting, "vertica_insert_dataframe", lambda **kwargs: captured.update(kwargs))

    out = reporting.sharepoint_to_vertica(
        sharepoint_conn="SP",
        file_url="/x.csv",
        table_name="mart.tbl",
        vertica_conn_id="VERT",
        mode="insert",
    )
    assert out["mode"] == "insert"
    assert captured["table_name"] == "mart.tbl"


def test_sharepoint_to_vertica_requires_unique_keys(monkeypatch):
    monkeypatch.setattr(reporting, "sharepoint_read_dataframe", lambda **kwargs: pd.DataFrame([{"id": 1}]))
    with pytest.raises(ValueError, match="unique_keys"):
        reporting.sharepoint_to_vertica(
            sharepoint_conn="SP",
            file_url="/x.csv",
            table_name="tbl",
            mode="upsert",
        )


def test_send_query_report_test_supports_creds_path(monkeypatch):
    df = pd.DataFrame([{"x": 1}])
    captured = {}

    monkeypatch.setattr(reporting, "vertica_select_test", lambda **kwargs: df)
    monkeypatch.setattr(
        reporting,
        "send_dataframe_preview_test",
        lambda **kwargs: None,
    )
    monkeypatch.setattr(
        reporting,
        "send_dataframe_as_csv_test",
        lambda **kwargs: captured.update(kwargs) or {"file_id": "F"},
    )
    monkeypatch.setattr(
        reporting,
        "post_message_test",
        lambda **kwargs: {"post_id": "P", "root_id": kwargs.get("root_id")},
    )

    out = reporting.send_query_report_test(
        channel_id="CH",
        bot_id="BOT",
        conn_id="VERT",
        sql="select 1",
        creds_path="/tmp/creds.json",
        header_text="h",
    )
    assert out["rows"] == 1
    assert captured["creds_path"] == "/tmp/creds.json"
