import json
import platform

import pytest
from voluptuous import Any, Schema

from dvc import analytics
from dvc.cli import parse_args


@pytest.fixture
def tmp_global_dir(mocker, tmp_path):
    """
    Fixture to prevent modifying the actual global config
    """

    def _user_config_dir(appname, *_args, **_kwargs):
        return str(tmp_path / appname)

    mocker.patch("iterative_telemetry.user_config_dir", _user_config_dir)


def test_collect_and_send_report(mocker, tmp_global_dir):
    mock_json = mocker.patch("json.dump")
    mock_daemon = mocker.patch("dvc.daemon._spawn")
    analytics.collect_and_send_report()
    report = mock_json.call_args[0][0]

    assert not report.get("cmd_class")
    assert not report.get("cmd_return_code")

    args = parse_args(["add", "foo"])
    return_code = 0

    analytics.collect_and_send_report(args, return_code)
    report = mock_json.call_args[0][0]

    assert report["cmd_class"] == "CmdAdd"
    assert report["cmd_return_code"] == return_code

    assert mock_daemon.call_count == 2


def test_runtime_info(tmp_global_dir):
    schema = Schema(
        {
            "dvc_version": str,
            "is_binary": bool,
            "scm_class": Any("Git", None),
            "user_id": str,
            "system_info": dict,
            "group_id": Any(str, None),
        },
        required=True,
    )

    assert schema(analytics._runtime_info())


def test_send(mocker, tmp_path):
    mock_post = mocker.patch("requests.post")

    import requests

    url = "https://analytics.dvc.org"
    report = {"name": "dummy report"}
    report_file = tmp_path / "report"

    report_file.write_text(json.dumps(report))
    mock_post.side_effect = requests.exceptions.RequestException

    analytics.send(str(report_file))
    assert mock_post.called
    assert mock_post.call_args[0][0] == url
    assert not report_file.exists()


@pytest.mark.parametrize(
    "config, result",
    [
        ({}, True),
        ({"analytics": "false"}, False),
        ({"analytics": "true"}, True),
        ({"unknown": "broken"}, True),
        ({"analytics": "false", "unknown": "broken"}, False),
    ],
)
def test_is_enabled(dvc, config, result, monkeypatch, tmp_global_dir):
    with dvc.config.edit(validate=False) as conf:
        conf["core"] = config

    # reset DVC_TEST env var, which affects `is_enabled()`
    monkeypatch.delenv("DVC_TEST")
    monkeypatch.delenv("DVC_NO_ANALYTICS", raising=False)

    assert result == analytics.is_enabled()


@pytest.mark.parametrize(
    "config, env, result",
    [
        (None, None, True),
        (None, "true", False),
        (None, "false", False),  # only checking if env is set
        ("false", None, False),
        ("false", "true", False),
        ("false", "false", False),
        ("true", None, True),
        ("true", "true", False),
        ("true", "false", False),  # we checking if env is set
    ],
)
def test_is_enabled_env_neg(dvc, config, env, result, monkeypatch, tmp_global_dir):
    # reset DVC_TEST env var, which affects `is_enabled()`
    monkeypatch.delenv("DVC_TEST")
    monkeypatch.delenv("DVC_NO_ANALYTICS", raising=False)

    with dvc.config.edit() as conf:
        conf["core"] = {}

    assert analytics.is_enabled()

    if config is not None:
        with dvc.config.edit() as conf:
            conf["core"] = {"analytics": config}

    if env is not None:
        monkeypatch.setenv("DVC_NO_ANALYTICS", env)

    assert result == analytics.is_enabled()


def test_system_info():
    schema = Schema({"os": Any("windows", "mac", "linux")}, required=True)

    system = platform.system()

    if system == "Windows":
        schema = schema.extend(
            {
                "windows_version_build": int,
                "windows_version_major": int,
                "windows_version_minor": int,
                "windows_version_service_pack": str,
            }
        )

    if system == "Darwin":
        schema = schema.extend({"mac_version": str})

    if system == "Linux":
        schema = schema.extend(
            {
                "linux_distro": str,
                "linux_distro_like": str,
                "linux_distro_version": str,
            }
        )

    assert schema(analytics._system_info())
