from __future__ import annotations
from enum import Enum

import pytest

from negmas.helpers import (
    create_loggers,
    pretty_string,
    shortest_unique_names,
    unique_name,
)
from negmas.helpers.inout import ConfigReader, is_nonzero_file


def test_shortest_names():
    lst = ["a.b.cat", "d.e.f", "a.d.cat"]
    assert shortest_unique_names(lst) == ["b.cat", "f", "d.cat"]
    assert shortest_unique_names(lst, max_compression=True) == ["b", "f", "d"]
    lst = ["a.b.cat", "a.b.cat", "d.e.f", "a.d.cat"]
    assert shortest_unique_names(lst) == ["a.b.cat", "a.b.cat", "f", "d.cat"]
    assert shortest_unique_names(lst, max_compression=True) == [
        "a.b.cat",
        "a.b.cat",
        "f",
        "d",
    ]
    result = shortest_unique_names(lst, guarantee_unique=True)
    assert len(set(result)) == 4
    assert result == ["cat0", "b.cat", "f", "d.cat"]
    result = shortest_unique_names(lst, max_compression=True, guarantee_unique=True)
    assert len(set(result)) == 4
    assert result == ["c", "b", "f", "d"]


def test_create_loggers_with_default_params(capsys):
    log = create_loggers()

    log.info("Test info")
    _, captured = capsys.readouterr()
    assert captured == ""


def disabled_test_create_loggers_with_file_params(capsys, tmpdir):
    file_name = tmpdir.join("log.txt")

    log = create_loggers(
        file_name=file_name, module_wide_log_file=True, app_wide_log_file=False
    )

    log.info("Test info")
    # _, captured = capsys.readouterr()
    # assert captured == ''

    # with open(file_name, 'r') as f:
    #     flog = f.read()
    #     assert flog.endswith('INFO - Test info\n')

    log.warning("Test message")
    # _, captured = capsys.readouterr()
    # assert captured.endswith('WARNING - Test message\n')

    # with open(file_name, 'r') as f:
    #     flog = f.read()
    #     assert flog.endswith('WARNING - Test message\n')


def test_unique_name_defaults():
    a = unique_name("")
    assert len(a) == 8 + 1 + 6 + 8 + 6


def test_unique_name_no_time():
    assert len(unique_name("", add_time=False)) == 8


def test_unique_name_with_path(tmpdir):
    a = unique_name(str(tmpdir))
    assert a.startswith(str(tmpdir))


def test_is_nonzero_file(tmpdir):
    f_name = unique_name("")
    f = tmpdir / f_name
    assert is_nonzero_file(f) is False

    with open(f, "w") as tst_file:
        tst_file.write("")
    assert is_nonzero_file(f) is False

    with open(f, "w") as tst_file:
        tst_file.write("test")
    assert is_nonzero_file(f) is True


def test_pretty_string(capsys):
    assert pretty_string("Test with no components") == "Test with no components"
    assert pretty_string(4) == "4"
    assert pretty_string(2.5) == "2.5"
    assert pretty_string([1, 2, 3]) == "[\n  1\n  2\n  3\n]"
    assert pretty_string((1, 2, 3)) == "[\n  1\n  2\n  3\n]"
    assert pretty_string({"a": 1, "b": 2}) == "{\n  a:1\n  b:2\n}"

    assert pretty_string([1, 2, 3], compact=True) == "[  1  2  3]"
    assert pretty_string((1, 2, 3), compact=True) == "[  1  2  3]"
    assert pretty_string({"a": 1, "b": 2}, compact=True) == '{  "a":1  "b":2}'


def test_config_reader():
    class A(ConfigReader):
        def __init__(self, a, b):
            self.a = a
            self.b = b

    test, _ = A.from_config(
        config={"a": 10, "b": [1, 2, 3]}, ignore_children=False, scope=locals()
    )
    assert isinstance(test, A)
    assert test.a == 10
    assert test.b == [1, 2, 3]


def test_config_reader_with_enum():
    class E(Enum):
        E1 = 1
        E2 = 2

    class A(ConfigReader):
        def __init__(self, a, b, e: E):
            self.a = a
            self.b = b
            self.e = e

    test, _ = A.from_config(
        config={"a": 10, "b": [1, 2, 3], "e:E": 1},
        ignore_children=False,
        scope=locals(),
    )
    assert isinstance(test, A)
    assert test.a == 10
    assert test.b == [1, 2, 3]
    assert test.e == E.E1


def test_config_reader_ignoring_children():
    class A(ConfigReader):
        def __init__(self, a, b):
            self.a = a
            self.b = b

    test = A.from_config(config={"a": 10, "b": [1, 2, 3]}, scope=locals())
    assert isinstance(test, A)
    assert test.a == 10
    assert test.b == [1, 2, 3]


class B(ConfigReader):
    def __init__(self, bb, bbdefault=5):
        self.bb = bb
        self.bbdefaults = bbdefault


class Other(ConfigReader):
    def __init__(self, o):
        self.o = o


class C(ConfigReader):
    def __init__(self, cc, b: B = None, others=None):
        self.cc = cc
        self.b = B
        self.others = others

    def set_others(self, others):
        self.others = others


class A(ConfigReader):
    def __init__(self, a, b=None, c=None):
        self.a = a
        self.b = b
        self.c = c


def test_config_reader_with_subobjects():
    test = A.from_config(
        config={
            "a": 10,
            "b": {"bb": 20},
            "c": {
                "cc": 5,
                "b": {"bb": 20},
                "others": [{"o": 1}, {"o": 2}, None, {"o": 3}],
            },
        },
        scope=globals(),
    )

    assert isinstance(test, A)
    assert test.a == 10
    assert isinstance(test.b, B)
    assert isinstance(test.c, C)
    assert isinstance(test.c.others, list)
    assert isinstance(test.c.others[0], Other)
    assert len(test.c.others) == 4
    assert test.c.others[2] is None


if __name__ == "__main__":
    pytest.main(args=[__file__])
