from datetime import timedelta
from pathlib import Path

import pandas as pd
import pytest

from avoca.bindings.qa_tool import export_EmpaQATool
from avoca.testing import testdata_dir
from avoca.testing.df import invalids_df, simple_df

export_path = testdata_dir / "export_empa_qa_tool"


@pytest.mark.parametrize(
    "df, name",
    [
        (simple_df, "simple"),
        (invalids_df, "invalids"),
    ],
)
def test_export_EmpaQATool(df, name):
    """Test the export_EmpaQATool function."""

    # Create a test dataframe
    df = df.copy()
    df[("compA", "flag")] = 0
    df[("compB", "flag")] = 0

    df[("-", "datetime")] = pd.date_range(start="2025-01-01", periods=len(df), freq="h")

    # Export the dataframe to a file
    export_file = export_EmpaQATool(
        df,
        export_path,
        datetime_offsets=(timedelta(minutes=-5), timedelta(minutes=0)),
        station=name,
    )

    # Check that the file is created
    assert Path(export_file).is_file()

    # Read the file and check that the data is correct
    df_exported = pd.read_csv(
        export_file,
        sep=";",
    )
    assert len(df_exported) == len(df)
    # Check that the 'compB-Value' column is of float dtype
    assert pd.api.types.is_float_dtype(df_exported["compB-Value"])
    assert not pd.isna(df_exported["compB-Value"]).any(), "NAN values must be 999..."


def _prepare_df_for_export(df: pd.DataFrame) -> pd.DataFrame:
    """Prepare a dataframe for export testing."""
    df = df.copy()
    df[("compA", "flag")] = 0
    df[("compB", "flag")] = 0
    df[("-", "datetime")] = pd.date_range(start="2025-01-01", periods=len(df), freq="h")
    df[("-", "datetime_start")] = df[("-", "datetime")] - timedelta(minutes=5)
    df[("-", "datetime_end")] = df[("-", "datetime")] + timedelta(minutes=0)
    return df


def test_export_names_dict():
    """test that export names from dict are used correctly."""

    out_file = export_EmpaQATool(
        _prepare_df_for_export(simple_df),
        export_path,
        export_names={"compA": "CustomCompA", "compB": "CustomCompB"},
        station="TEST_DICT",
    )

    df_exported = pd.read_csv(
        out_file,
        sep=";",
    )

    assert "CustomCompA-Value" in df_exported.columns
    assert "CustomCompB-Value" in df_exported.columns
    assert "compA-Value" not in df_exported.columns
    assert "compB-Value" not in df_exported.columns


def test_export_names_df():
    """test that export names from dict are used correctly."""

    out_file = export_EmpaQATool(
        _prepare_df_for_export(simple_df),
        export_path,
        station="TEST_NAMES_DF",
        df_substances=pd.DataFrame(
            {
                "substance": ["compA", "compB"],
                "export_name": ["CustomCompA", "CustomCompB"],
            }
        ).set_index("substance"),
    )

    df_exported = pd.read_csv(
        out_file,
        sep=";",
    )

    assert "CustomCompA-Value" in df_exported.columns
    assert "CustomCompB-Value" in df_exported.columns
    assert "compA-Value" not in df_exported.columns
    assert "compB-Value" not in df_exported.columns


def test_both_export_names_warns(caplog):
    """test that export names from dict are used correctly."""

    with caplog.at_level("WARNING"):
        out_file = export_EmpaQATool(
            _prepare_df_for_export(simple_df),
            export_path,
            station="TEST_BOTH_WARN",
            export_names={"compA": "CustomCompA", "compB": "CustomCompB"},
            df_substances=pd.DataFrame(
                {
                    "substance": ["compA", "compB"],
                    "export_name": ["WrongCompA", "CustomCompB"],
                }
            ).set_index("substance"),
        )

    assert (
        "Substance compA found in both df_substances and export_names." in caplog.text
    )

    df_exported = pd.read_csv(
        out_file,
        sep=";",
    )

    assert "CustomCompA-Value" in df_exported.columns
    assert "CustomCompB-Value" in df_exported.columns
    assert "compA-Value" not in df_exported.columns
    assert "WrongCompA-Value" not in df_exported.columns
    assert "compB-Value" not in df_exported.columns


def test_export_no_export_substances():
    """test that substances with export=False in df_substances are not exported."""

    out_file = export_EmpaQATool(
        _prepare_df_for_export(simple_df),
        export_path,
        station="TEST_NO_EXPORT_SUBSTANCES",
        df_substances=pd.DataFrame(
            {
                "substance": ["compA", "compB"],
                "export": [True, False],
            }
        ).set_index("substance"),
    )

    df_exported = pd.read_csv(
        out_file,
        sep=";",
    )

    assert "compA-Value" in df_exported.columns
    assert "compB-Value" not in df_exported.columns


def test_export_if_not_in_df_substances():
    """test that substances not in df_substances are exported."""

    out_file = export_EmpaQATool(
        _prepare_df_for_export(simple_df),
        export_path,
        station="TEST_IF_NOT_IN_DF_SUBSTANCES",
        df_substances=pd.DataFrame(
            {
                "substance": ["compA"],
                "export": [True],
            }
        ).set_index("substance"),
    )

    df_exported = pd.read_csv(
        out_file,
        sep=";",
    )

    assert "compA-Value" in df_exported.columns
    assert "compB-Value" in df_exported.columns


def test_export_and_rename_in_df_substances():
    """test that export names from dict are used correctly."""

    out_file = export_EmpaQATool(
        _prepare_df_for_export(simple_df),
        export_path,
        station="TEST_EXPORT_AND_RENAME_IN_DF_SUBSTANCES",
        df_substances=pd.DataFrame(
            {
                "substance": ["compA", "compB"],
                "export_name": ["CustomCompA", "CustomCompB"],
                "export": [True, False],
            }
        ).set_index("substance"),
    )

    df_exported = pd.read_csv(
        out_file,
        sep=";",
    )

    assert "CustomCompA-Value" in df_exported.columns
    assert "compA-Value" not in df_exported.columns
    assert "compB-Value" not in df_exported.columns
    assert "CustomCompB-Value" not in df_exported.columns
