import pathlib
import re
import tempfile
from typing import Iterator

import pytest
import tomlkit

from pysen import dumper
from pysen.setting import SettingFile

MULTIPLE_SPACES = re.compile(r"\s+")
TOOL_HEADING = "[tool]\n"


def normalize_spaces(s: str) -> str:
    return MULTIPLE_SPACES.sub(" ", s)


@pytest.fixture
def test_data() -> SettingFile:
    foo = {
        "hoge": True,
        "fuga": ["c", "A", "B", "d"],
        "piyo": "description",
    }
    bar = {
        "c": "yes",
        "a": 1.0,
        "b": 12345,
    }

    s = SettingFile()
    s.set_section(["foo"], foo)
    s.set_section(["bar"], bar)
    return s


@pytest.fixture
def test_nested_data() -> SettingFile:
    foo = {
        "piyo": "description",
        "hoge": True,
        "fuga": ["c", "A", "B", "d"],
        "hogehoge": {"z": ["1", "3", "2"], "x": "Hello", "y": 42},
    }
    bar = {
        "c": "yes",
        "a": 1.0,
        "b": 12345,
        "d": {"d-2": "hoge", "d-1": {"d-1-b": True, "d-1-a": False, "d-1-c": True}},
    }

    s = SettingFile()
    s.set_section(["tool", "foo"], foo)
    s.set_section(["tool", "bar"], bar)
    return s


@pytest.fixture
def temp_file() -> Iterator[pathlib.Path]:
    with tempfile.NamedTemporaryFile() as tmp:
        yield pathlib.Path(tmp.name)


def _assert_toml(path: pathlib.Path, expected: SettingFile) -> None:
    with path.open("r") as f:
        data = dict(tomlkit.loads(f.read()))

    assert data == expected.as_dict()


def test_dump_toml(temp_file: pathlib.Path, test_nested_data: SettingFile) -> None:
    dumper.dump_toml(temp_file, test_nested_data)
    expected = """[tool.bar] # automatically generated by pysen
# pysen ignores and overwrites any modifications
a = 1.0
b = 12345
c = "yes"
[tool.bar.d]
d-2 = "hoge"
[tool.bar.d.d-1]
d-1-a = false
d-1-b = true
d-1-c = true
[tool.foo] # automatically generated by pysen
# pysen ignores and overwrites any modifications
fuga = ["A", "B", "c", "d"]
hoge = true
piyo = "description"
[tool.foo.hogehoge]
    x = "Hello"
    y = 42
    z = ["1", "2", "3"]
"""

    with temp_file.open("r") as f:
        actual = f.read()

    # NOTE: tomlkit 0.10+ won't create a super table if the table has only one child
    if actual.startswith(TOOL_HEADING):
        actual = actual[len(TOOL_HEADING) :]
    assert normalize_spaces(actual) == normalize_spaces(expected)


def test_dump_cfg(temp_file: pathlib.Path, test_data: SettingFile) -> None:
    dumper.dump_cfg(temp_file, test_data)
    expected = """[bar]
# automatically generated by pysen
# pysen ignores and overwrites any modifications
a = 1.0
b = 12345
c = yes
[foo]
# automatically generated by pysen
# pysen ignores and overwrites any modifications
fuga = A,B,c,d
hoge = True
piyo = description
"""
    with temp_file.open("r") as f:
        actual = f.read()

    assert normalize_spaces(actual) == normalize_spaces(expected)


def test_dump(test_data: SettingFile) -> None:
    with tempfile.TemporaryDirectory() as tmp:
        d = pathlib.Path(tmp)
        dumper.dump(d, "hoge.toml", test_data)
        dumper.dump(d, "hoge.cfg", test_data)

        with pytest.raises(RuntimeError):
            dumper.dump(d, "hoge.bin", test_data)
