# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: Ansible Project

import argparse

import antsibull_core.app_context as ap
from antsibull_core.schemas.config import LoggingModel
from antsibull_core.utils.collections import ContextDict

#
# Context creation tests
#


def test_default():
    """Context has default values if no ocntext manager is used"""
    lib_ctx = ap.lib_ctx.get()
    assert lib_ctx.chunksize == 4096
    assert lib_ctx.process_max is None
    assert lib_ctx.thread_max == 8
    assert lib_ctx.max_retries == 10

    app_ctx = ap.app_ctx.get()
    assert app_ctx.extra == ContextDict()
    assert app_ctx.galaxy_url == "https://galaxy.ansible.com/"
    assert isinstance(app_ctx.logging_cfg, LoggingModel)
    assert app_ctx.pypi_url == "https://pypi.org/"


def test_create_contexts_with_cfg():
    """Test that the create_contexts function sets values from a config dict"""
    cfg = {"chunksize": 1, "pypi_url": "https://test.pypi.org/", "unknown": True}
    app_ctx, lib_ctx, args, cfg = ap.create_contexts(cfg=cfg)

    assert args == argparse.Namespace()
    assert cfg == {}

    assert lib_ctx.chunksize == 1
    assert lib_ctx.process_max is None
    assert lib_ctx.thread_max == 8
    assert lib_ctx.max_retries == 10

    assert app_ctx.extra == ContextDict({"unknown": True})
    assert app_ctx.galaxy_url == "https://galaxy.ansible.com/"
    assert isinstance(app_ctx.logging_cfg, LoggingModel)
    assert app_ctx.pypi_url == "https://test.pypi.org/"


def test_create_contexts_with_args():
    """Test that the create_context function sets values from cli args"""
    args = {"process_max": 2, "pypi_url": "https://test.pypi.org/", "unknown": True}
    args = argparse.Namespace(**args)
    app_ctx, lib_ctx, args, cfg = ap.create_contexts(args=args)

    assert args == argparse.Namespace()
    assert cfg == {}

    assert lib_ctx.chunksize == 4096
    assert lib_ctx.process_max == 2
    assert lib_ctx.thread_max == 8
    assert lib_ctx.max_retries == 10

    assert app_ctx.extra == ContextDict({"unknown": True})
    assert app_ctx.galaxy_url == "https://galaxy.ansible.com/"
    assert isinstance(app_ctx.logging_cfg, LoggingModel)
    assert app_ctx.pypi_url == "https://test.pypi.org/"


def test_create_contexts_with_args_and_cfg():
    """Test that args override cfg"""
    cfg = {
        "chunksize": 1,
        "thread_max": 2,
        "galaxy_url": "https://dev.galaxy.ansible.com/",
        "pypi_url": "https://test.pypi.org/",
        "unknown": True,
        "cfg": 1,
    }
    args = {
        "chunksize": 3,
        "pypi_url": "https://other.pypi.org/",
        "unknown": False,
        "args": 2,
    }
    args = argparse.Namespace(**args)
    app_ctx, lib_ctx, args, cfg = ap.create_contexts(args=args, cfg=cfg)

    assert args == argparse.Namespace()
    assert cfg == {}

    assert lib_ctx.chunksize == 3
    assert lib_ctx.process_max is None
    assert lib_ctx.thread_max == 2
    assert lib_ctx.max_retries == 10

    assert app_ctx.extra == ContextDict({"unknown": False, "cfg": 1, "args": 2})
    assert app_ctx.galaxy_url == "https://dev.galaxy.ansible.com/"
    assert isinstance(app_ctx.logging_cfg, LoggingModel)
    assert app_ctx.pypi_url == "https://other.pypi.org/"


def test_create_contexts_without_extra():
    """Test that use_extra=False returns unused args and cfg."""
    cfg_data = {"chunksize": 7, "unknown": True, "cfg": 1}
    args_data = {"thread_max": 10, "unknown": False, "args": 2}
    input_args = argparse.Namespace(**args_data)
    app_ctx, lib_ctx, args, cfg = ap.create_contexts(
        args=input_args, cfg=cfg_data, use_extra=False
    )

    assert args == argparse.Namespace(unknown=False, args=2)
    assert cfg == {"unknown": True, "cfg": 1}

    assert lib_ctx.chunksize == 7
    assert lib_ctx.process_max is None
    assert lib_ctx.thread_max == 10
    assert lib_ctx.max_retries == 10

    assert app_ctx.extra == ContextDict()
    assert app_ctx.galaxy_url == "https://galaxy.ansible.com/"
    assert isinstance(app_ctx.logging_cfg, LoggingModel)
    assert app_ctx.pypi_url == "https://pypi.org/"


#
# Context manager tests
#


def test_context_overrides():
    data = ap.create_contexts(
        cfg={"chunksize": 5, "galaxy_url": "https://dev.galaxy.ansible.com/"}
    )

    with ap.app_context(data.app_ctx) as app_ctx:
        # Test that the app_context that was returned has the new values
        assert app_ctx.galaxy_url == "https://dev.galaxy.ansible.com/"

        # Test that the context that we can retrieve has the new values too
        app_ctx = ap.app_ctx.get()
        assert app_ctx.galaxy_url == "https://dev.galaxy.ansible.com/"

    with ap.lib_context(data.lib_ctx) as lib_ctx:
        # Test that the returned lib_ctx has the new values
        assert lib_ctx.chunksize == 5

        # Likewise for the one that we can retrieve
        lib_ctx = ap.lib_ctx.get()
        assert lib_ctx.chunksize == 5

    # Check that once we return from the context managers, the old values have been restored
    app_ctx = ap.app_ctx.get()
    assert app_ctx.extra == ContextDict()
    assert app_ctx.galaxy_url == "https://galaxy.ansible.com/"
    assert isinstance(app_ctx.logging_cfg, LoggingModel)
    assert app_ctx.pypi_url == "https://pypi.org/"

    lib_ctx = ap.lib_ctx.get()
    assert lib_ctx.chunksize == 4096
    assert lib_ctx.process_max is None
    assert lib_ctx.thread_max == 8
    assert lib_ctx.max_retries == 10


def test_manager_creates_new_context():
    orig_app_ctx = ap.app_ctx.get()
    with ap.app_context() as app_ctx:
        new_app_ctx = ap.app_ctx.get()
        # Test that the app_ctx that was returned is the same as the one that is now set
        assert app_ctx is new_app_ctx

        # Test that the new app_ctx is different than the old one
        assert new_app_ctx is not orig_app_ctx

        # Test that the app_ctx that was returned has the same values as the old context
        assert new_app_ctx == orig_app_ctx

    orig_lib_ctx = ap.lib_ctx.get()
    with ap.lib_context() as lib_ctx:
        new_lib_ctx = ap.lib_ctx.get()
        # Test that the lib_ctx that was returned is the same as the one that is now set
        assert lib_ctx is new_lib_ctx

        # Test that the new lib_ctx is different than the old one
        assert new_lib_ctx is not orig_lib_ctx

        # Test that the lib_ctx that was returned has the same values as the old context
        assert new_lib_ctx == orig_lib_ctx

    # Check that once we return from the context managers, the old contexts have been returned
    assert orig_app_ctx is ap.app_ctx.get()
    assert orig_lib_ctx is ap.lib_ctx.get()


def test_app_and_lib_context():
    data = ap.create_contexts(
        cfg={"chunksize": 5, "galaxy_url": "https://dev.galaxy.ansible.com/"}
    )

    with ap.app_and_lib_context(data) as (app_ctx, lib_ctx):
        # Test that the app_context that was returned has the new values
        assert app_ctx.galaxy_url == "https://dev.galaxy.ansible.com/"

        # Test that the context that we can retrieve has the new values too
        app_ctx = ap.app_ctx.get()
        assert app_ctx.galaxy_url == "https://dev.galaxy.ansible.com/"

        # Test that the returned lib_ctx has the new values
        assert lib_ctx.chunksize == 5

        # Likewise for the one that we can retrieve
        lib_ctx = ap.lib_ctx.get()
        assert lib_ctx.chunksize == 5

    # Check that once we return from the context manager, the old values have been restored
    app_ctx = ap.app_ctx.get()
    assert app_ctx.extra == ContextDict()
    assert app_ctx.galaxy_url == "https://galaxy.ansible.com/"
    assert isinstance(app_ctx.logging_cfg, LoggingModel)
    assert app_ctx.pypi_url == "https://pypi.org/"

    lib_ctx = ap.lib_ctx.get()
    assert lib_ctx.chunksize == 4096
    assert lib_ctx.process_max is None
    assert lib_ctx.thread_max == 8
    assert lib_ctx.max_retries == 10
