from oaa.run import main
from pathlib import Path
from oaa.settings import Config
from oaa.settings_utils import SourceType
import pytest
import os


requires_db = pytest.mark.skipif(
    not os.environ.get("DB_PASSWORD"),
    reason="requires DB_PASSWORD environment variable",
)


LOG_LEVELS = ["DEBUG", "INFO", "TRACE", "ERROR"]


def test_run_help(capsys):

    main(cli_args=["custom_app", "--help"])

    captured = capsys.readouterr()

    output_expected = [
        "oaa",
        "--help",
        "COMMAND is one of the following:",
    ]

    for output in output_expected:
        # print(captured.out)
        assert output in captured.out

    # print('-' * 20)


@requires_db
def test_run_with_config(capsys):

    from pathlib import Path
    import os

    BASE_DIR = Path(os.path.dirname(os.path.realpath(__file__)))

    main(
        cli_args=[
            "custom_app",
            "show_config",
            "--config-file",
            str(BASE_DIR / "config-v2.yaml"),
            "--config-file-yaml",
            "true",
        ]
    )

    captured = capsys.readouterr()

    output_expected = [
        '"log_level"',
        "config_file",
    ]

    for output in output_expected:
        # print(captured.out)
        assert output in captured.out

    # print('-' * 20)


@pytest.mark.parametrize("log_level", LOG_LEVELS)
def test_new_singleton_config(log_level, config):
    os.environ["log_level"] = log_level
    assert os.getenv("log_level") == log_level
    config.update()
    assert Config.get("log_level") == log_level
    assert config.get("log_level") == log_level


@pytest.mark.parametrize("log_level", LOG_LEVELS)
def test_new_singleton_config_2(log_level, config):
    os.environ["log_level"] = log_level
    assert os.getenv("log_level") == log_level
    config.update()
    assert Config.get("log_level") == log_level
    assert config.LOG_LEVEL == log_level


@requires_db
def test_load_from_config_file(config):
    config.update(config_file="./tests/config-v2.yaml")

    assert config.LOG_LEVEL == "ERROR"

    should_be = Path(os.path.dirname(__file__)) / "data/resources_mapping.csv"
    assert config.sources["apps"].mapping_filepath == should_be


@requires_db
def test_mod_folder(config):
    """
    We can write custom functions for manipulating data as needed.

    A mod function is created by decorating a function with the @transformer
    decorator found in oaa.utils

    The decorator takes two parameters:
    :table: the stream of data
    :config: the configuration object

    The mod function must return a streaming object
    """
    from oaa.settings_v2 import ConfigV2

    config.update(config_file="./tests/config-v2.yaml", config_format="yaml")
    assert config.version == "v2"
    assert isinstance(config._CONFIG, ConfigV2)
    assert config.MODULE_DIRECTORY
    assert config.module_directory
    mod_folder_should_be = Path(os.path.dirname(__file__)) / "modules"

    assert config.module_directory == mod_folder_should_be


# ============================================================================
# Tests for ConfigV2.post_update() model_validator
# ============================================================================


def _make_post_update_config(sources: dict):
    """Build a minimal ConfigV2 with the given sources dict.

    Uses source_type=VEZA_API which requires no filepath — avoids the
    destination=None bypass and keeps sources realistic.
    """
    from oaa.settings_config import ConfigV2
    return ConfigV2.model_validate({
        'version': 'v2',
        'runner_type': 'HRIS',
        'sources': sources,
    })


def test_post_update_sets_source_names():
    """source_name is populated from the config key for each source."""
    config = _make_post_update_config({
        'employees': {'source_type': 'VEZA_API'},
        'roles': {'source_type': 'VEZA_API'},
    })

    assert config.sources['employees'].source_name == 'employees'
    assert config.sources['roles'].source_name == 'roles'


def test_post_update_sets_is_csv_push_when_present():
    """is_csv_push is True when at least one source has source_type=csv_push."""
    config = _make_post_update_config({
        'employees': {'source_type': 'VEZA_API'},
        'org_chart': {'source_type': 'CSV_PUSH'},
    })

    assert config.is_csv_push is True


def test_post_update_keeps_is_csv_push_false():
    """is_csv_push stays False when no csv_push sources exist."""
    config = _make_post_update_config({
        'employees': {'source_type': 'VEZA_API'},
        'roles': {'source_type': 'VEZA_API'},
    })

    assert config.is_csv_push is False
