"""Unit tests for utils/file.py"""

import json
import pytest
from unittest.mock import patch, MagicMock

with (
    patch("gmi_ieops.utils.file.log", MagicMock()),
    patch("gmi_ieops.handler.client.uvicorn_logger", MagicMock()),
    patch("gmi_ieops.handler.client.env", MagicMock()),
):
    from gmi_ieops.utils.file import load_json, save_json, save, _write_file


class TestJsonIO:

    def test_roundtrip(self, tmp_path):
        f = str(tmp_path / "d.json")
        save_json(f, {"k": "v", "n": [1, 2]})
        assert load_json(f) == {"k": "v", "n": [1, 2]}

    def test_overwrite(self, tmp_path):
        f = str(tmp_path / "d.json")
        save_json(f, {"a": 1}); save_json(f, {"b": 2})
        assert load_json(f) == {"b": 2}

    def test_invalid_raises(self, tmp_path):
        (tmp_path / "bad.json").write_text("nope")
        with pytest.raises(json.JSONDecodeError):
            load_json(str(tmp_path / "bad.json"))


class TestWriteFile:

    @pytest.mark.parametrize("data,mode,reader,expected", [
        (b"\x00\x01", "w", "read_bytes", b"\x00\x01"),
        ("hello", "w", "read_text", "hello"),
        ("你好 🌍", "w", "read_text", "你好 🌍"),
    ])
    def test_basic_writes(self, tmp_path, data, mode, reader, expected):
        f = tmp_path / "out"
        _write_file(str(f), data, mode)
        assert getattr(f, reader)() == expected

    def test_dict_overwrite_and_append(self, tmp_path):
        f = tmp_path / "d.jsonl"
        _write_file(str(f), {"a": 1})
        assert json.loads(f.read_text()) == {"a": 1}
        f.unlink()
        _write_file(str(f), {"a": 1}, "a"); _write_file(str(f), {"b": 2}, "a")
        lines = f.read_text().strip().split("\n")
        assert [json.loads(l) for l in lines] == [{"a": 1}, {"b": 2}]

    def test_append_str_and_bytes(self, tmp_path):
        f = tmp_path / "log"
        _write_file(str(f), "L1\n", "w"); _write_file(str(f), "L2\n", "a")
        assert f.read_text() == "L1\nL2\n"

        fb = tmp_path / "bin"
        _write_file(str(fb), b"\x00", "w"); _write_file(str(fb), b"\x01", "a")
        assert fb.read_bytes() == b"\x00\x01"

    def test_unsupported_type_raises(self, tmp_path):
        with pytest.raises(TypeError, match="Unsupported"):
            _write_file(str(tmp_path / "x"), 12345)


class TestSave:

    def test_success_and_failure(self, tmp_path):
        assert save(str(tmp_path / "ok.txt"), "data") is None
        assert isinstance(save("/", "data"), Exception)
