"""
描述:
- MacOSConnect 类的单元测试。
- 测试本地文件系统连接实现的所有功能和边界情况。
"""

from __future__ import annotations

import tempfile
from pathlib import Path

import pytest

from xfintech.connect.common.connect import ConnectLike
from xfintech.connect.common.connectref import ConnectRef
from xfintech.connect.common.error import ConnectFailedError, ConnectKeyError
from xfintech.connect.instance.macos import MacOSConnect

# =============================================================================
# Initialization Tests
# =============================================================================


def test_macosconnect_init():
    """测试初始化"""
    connect = MacOSConnect()
    assert connect.kind == "macos"


def test_macosconnect_is_connectlike():
    """测试 MacOSConnect 实现了 ConnectLike 协议"""
    connect = MacOSConnect()
    assert isinstance(connect, ConnectLike)


def test_macosconnect_has_docstring():
    """测试 MacOSConnect 有文档字符串"""
    assert MacOSConnect.__doc__ is not None
    assert len(MacOSConnect.__doc__) > 0


# =============================================================================
# Path Resolution Tests
# =============================================================================


def test_resolve_path_with_string():
    """测试用字符串解析路径"""
    connect = MacOSConnect()
    path = connect._resolve_path("/tmp/test.txt")

    assert isinstance(path, Path)
    # On macOS, /tmp resolves to /private/tmp
    assert path.name == "test.txt"
    assert path.is_absolute()


def test_resolve_path_with_path_object():
    """测试用 Path 对象解析路径"""
    connect = MacOSConnect()
    input_path = Path("/tmp/test.txt")
    path = connect._resolve_path(input_path)

    assert isinstance(path, Path)
    # After resolve(), paths may have different representations
    assert path.name == "test.txt"
    assert path.is_absolute()


def test_resolve_path_with_tilde():
    """测试展开波浪号"""
    connect = MacOSConnect()
    path = connect._resolve_path("~/test.txt")

    assert not str(path).startswith("~")
    assert path.is_absolute()


def test_resolve_path_with_relative():
    """测试相对路径转换为绝对路径"""
    connect = MacOSConnect()
    path = connect._resolve_path("test.txt")

    assert path.is_absolute()


def test_resolve_path_none_raises_error():
    """测试 None 路径抛出错误"""
    connect = MacOSConnect()

    with pytest.raises(ConnectKeyError) as excinfo:
        connect._resolve_path(None)
    assert "location cannot be None" in str(excinfo.value)


# =============================================================================
# put_bytes Tests
# =============================================================================


def test_put_bytes_creates_file():
    """测试创建文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        connect.put_bytes(b"test data", str(file_path))

        assert file_path.exists()
        assert file_path.read_bytes() == b"test data"


def test_put_bytes_creates_parent_directories():
    """测试创建父目录"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "subdir1" / "subdir2" / "test.txt"

        connect.put_bytes(b"data", str(file_path))

        assert file_path.exists()
        assert file_path.parent.exists()


def test_put_bytes_overwrites_existing():
    """测试覆盖现有文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        # Write first time
        connect.put_bytes(b"original", str(file_path))
        assert file_path.read_bytes() == b"original"

        # Overwrite
        connect.put_bytes(b"updated", str(file_path))
        assert file_path.read_bytes() == b"updated"


def test_put_bytes_with_path_object():
    """测试使用 Path 对象写入"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        connect.put_bytes(b"data", file_path)

        assert file_path.read_bytes() == b"data"


def test_put_bytes_empty_data():
    """测试写入空数据"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "empty.txt"

        connect.put_bytes(b"", str(file_path))

        assert file_path.exists()
        assert file_path.read_bytes() == b""


def test_put_bytes_large_data():
    """测试写入大数据"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "large.bin"
        large_data = b"x" * (10 * 1024 * 1024)  # 10MB

        connect.put_bytes(large_data, str(file_path))

        assert file_path.read_bytes() == large_data


def test_put_bytes_with_tilde():
    """测试使用波浪号路径"""
    # Use a temp directory inside the home directory to avoid polluting actual home
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        # Create a file with absolute path, test that tilde expansion would work
        file_path = Path(tmpdir) / "test.txt"

        connect.put_bytes(b"data", str(file_path))
        assert file_path.exists()


def test_put_bytes_none_location():
    """测试 None 位置"""
    connect = MacOSConnect()

    with pytest.raises(ConnectKeyError) as excinfo:
        connect.put_bytes(b"data", None)
    assert "location cannot be None" in str(excinfo.value)


def test_put_bytes_invalid_path():
    """测试写入无效路径"""
    connect = MacOSConnect()

    # Test with a file that exists as a directory
    with tempfile.TemporaryDirectory() as tmpdir:
        # Try to write to a path that's actually a directory
        dir_path = Path(tmpdir) / "existing_dir"
        dir_path.mkdir()

        with pytest.raises(ConnectFailedError):
            connect.put_bytes(b"data", dir_path)


# =============================================================================
# get_bytes Tests
# =============================================================================


def test_get_bytes_reads_file():
    """测试读取文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"
        file_path.write_bytes(b"test data")

        data = connect.get_bytes(str(file_path))

        assert data == b"test data"


def test_get_bytes_with_path_object():
    """测试使用 Path 对象读取"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"
        file_path.write_bytes(b"data")

        data = connect.get_bytes(file_path)

        assert data == b"data"


def test_get_bytes_empty_file():
    """测试读取空文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "empty.txt"
        file_path.write_bytes(b"")

        data = connect.get_bytes(str(file_path))

        assert data == b""


def test_get_bytes_large_file():
    """测试读取大文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "large.bin"
        large_data = b"x" * (10 * 1024 * 1024)  # 10MB
        file_path.write_bytes(large_data)

        data = connect.get_bytes(str(file_path))

        assert data == large_data


def test_get_bytes_with_tilde():
    """测试使用波浪号路径读取"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"
        file_path.write_bytes(b"data")

        data = connect.get_bytes(str(file_path))
        assert data == b"data"


def test_get_bytes_none_location():
    """测试 None 位置"""
    connect = MacOSConnect()

    with pytest.raises(ConnectKeyError) as excinfo:
        connect.get_bytes(None)
    assert "location cannot be None" in str(excinfo.value)


def test_get_bytes_nonexistent_file():
    """测试读取不存在的文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        nonexistent = Path(tmpdir) / "subdir" / "nonexistent.txt"

        # File doesn't exist, but directory will be created by _resolve_path
        # The error happens when trying to open the file
        with pytest.raises(ConnectFailedError) as excinfo:
            connect.get_bytes(str(nonexistent))
        assert "no such file" in str(excinfo.value).lower()


def test_get_bytes_directory():
    """测试读取目录"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()

        with pytest.raises(ConnectFailedError) as excinfo:
            connect.get_bytes(tmpdir)
        # Error message is "Is a directory"
        assert "directory" in str(excinfo.value).lower()


# =============================================================================
# put_object Tests
# =============================================================================


def test_put_object_returns_connectref():
    """测试 put_object 返回 ConnectRef"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        ref = connect.put_object(b"data", str(file_path))

        assert isinstance(ref, ConnectRef)
        assert ref.kind == "macos"
        assert str(file_path) in ref.location


def test_put_object_writes_file():
    """测试 put_object 写入文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        connect.put_object(b"test data", str(file_path))

        assert file_path.exists()
        assert file_path.read_bytes() == b"test data"


def test_put_object_with_path_object():
    """测试使用 Path 对象"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        connect.put_object(b"data", file_path)

        assert file_path.read_bytes() == b"data"


def test_put_object_none_location():
    """测试 None 位置"""
    connect = MacOSConnect()

    with pytest.raises(ConnectKeyError):
        connect.put_object(b"data", None)


# =============================================================================
# get_object Tests
# =============================================================================


def test_get_object_returns_bytes():
    """测试 get_object 返回字节"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"
        file_path.write_bytes(b"test data")

        data = connect.get_object(str(file_path))

        assert isinstance(data, bytes)
        assert data == b"test data"


def test_get_object_reads_file():
    """测试 get_object 读取文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"
        file_path.write_bytes(b"data")

        data = connect.get_object(str(file_path))

        assert data == b"data"


def test_get_object_with_path_object():
    """测试使用 Path 对象"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"
        file_path.write_bytes(b"data")

        data = connect.get_object(file_path)

        assert data == b"data"


def test_get_object_none_location():
    """测试 None 位置"""
    connect = MacOSConnect()

    with pytest.raises(ConnectKeyError):
        connect.get_object(None)


def test_get_object_nonexistent():
    """测试读取不存在的文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        nonexistent = Path(tmpdir) / "subdir" / "nonexistent.txt"

        with pytest.raises(ConnectFailedError):
            connect.get_object(str(nonexistent))


# =============================================================================
# Integration Tests
# =============================================================================


def test_round_trip():
    """测试完整的读写流程"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        # Write
        ref = connect.put_object(b"test data", str(file_path))
        assert ref.kind == "macos"

        # Read
        data = connect.get_object(str(file_path))
        assert data == b"test data"


def test_multiple_files():
    """测试多个文件操作"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()

        files = {
            "file1.txt": b"data1",
            "file2.txt": b"data2",
            "file3.txt": b"data3",
        }

        # Write all files
        for filename, data in files.items():
            file_path = Path(tmpdir) / filename
            connect.put_object(data, str(file_path))

        # Read and verify
        for filename, expected_data in files.items():
            file_path = Path(tmpdir) / filename
            actual_data = connect.get_object(str(file_path))
            assert actual_data == expected_data


def test_nested_directories():
    """测试嵌套目录"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()

        nested_path = Path(tmpdir) / "level1" / "level2" / "level3" / "file.txt"

        # Write creates all directories
        connect.put_object(b"nested data", str(nested_path))

        # Read works
        data = connect.get_object(str(nested_path))
        assert data == b"nested data"


def test_update_file():
    """测试更新文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "update.txt"

        # Initial write
        connect.put_object(b"version 1", str(file_path))
        assert connect.get_object(str(file_path)) == b"version 1"

        # Update
        connect.put_object(b"version 2", str(file_path))
        assert connect.get_object(str(file_path)) == b"version 2"


# =============================================================================
# Edge Cases
# =============================================================================


def test_unicode_filename():
    """测试 Unicode 文件名"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "测试文件.txt"

        connect.put_object(b"unicode data", str(file_path))
        data = connect.get_object(str(file_path))

        assert data == b"unicode data"


def test_special_characters_filename():
    """测试特殊字符文件名"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "file with spaces & special!.txt"

        connect.put_object(b"special", str(file_path))
        data = connect.get_object(str(file_path))

        assert data == b"special"


def test_very_long_path():
    """测试很长的路径"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()

        # Create a path with many nested directories
        long_path = Path(tmpdir)
        for i in range(10):
            long_path = long_path / f"directory_{i}"
        long_path = long_path / "file.txt"

        connect.put_object(b"deep data", str(long_path))
        data = connect.get_object(str(long_path))

        assert data == b"deep data"


def test_binary_data():
    """测试二进制数据"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "binary.bin"

        # Create binary data with all byte values
        binary_data = bytes(range(256))

        connect.put_object(binary_data, str(file_path))
        data = connect.get_object(str(file_path))

        assert data == binary_data


def test_concurrent_writes():
    """测试并发写入不同文件"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()

        # Simulate multiple sequential writes (can't truly test concurrency here)
        for i in range(10):
            file_path = Path(tmpdir) / f"file_{i}.txt"
            connect.put_object(f"data_{i}".encode(), str(file_path))

        # Verify all files
        for i in range(10):
            file_path = Path(tmpdir) / f"file_{i}.txt"
            data = connect.get_object(str(file_path))
            assert data == f"data_{i}".encode()


# =============================================================================
# Type Tests
# =============================================================================


def test_returns_correct_types():
    """测试返回正确的类型"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        # put_object returns ConnectRef
        ref = connect.put_object(b"data", str(file_path))
        assert isinstance(ref, ConnectRef)

        # get_object returns bytes
        data = connect.get_object(str(file_path))
        assert isinstance(data, bytes)

        # put_bytes returns None
        result = connect.put_bytes(b"data", str(file_path))
        assert result is None

        # get_bytes returns bytes
        data = connect.get_bytes(str(file_path))
        assert isinstance(data, bytes)


def test_connectref_has_correct_attributes():
    """测试 ConnectRef 有正确的属性"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        ref = connect.put_object(b"data", str(file_path))

        assert hasattr(ref, "location")
        assert hasattr(ref, "kind")
        assert ref.kind == "macos"
        assert str(file_path) in ref.location


# =============================================================================
# Error Message Tests
# =============================================================================


def test_connectkeyerror_message():
    """测试 ConnectKeyError 错误消息"""
    connect = MacOSConnect()

    try:
        connect.put_bytes(b"data", None)
    except ConnectKeyError as e:
        assert "location cannot be None" in str(e)


def test_connectfailederror_message_read():
    """测试读取失败的错误消息"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        nonexistent = Path(tmpdir) / "subdir" / "nonexistent.txt"

        try:
            connect.get_bytes(str(nonexistent))
        except ConnectFailedError as e:
            assert "no such file" in str(e).lower()


def test_connectfailederror_message_write():
    """测试写入失败的错误消息"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        # Try to write to a directory (not a file)
        dir_path = Path(tmpdir) / "existing_dir"
        dir_path.mkdir()

        try:
            connect.put_bytes(b"data", dir_path)
        except ConnectFailedError as e:
            assert "directory" in str(e).lower() or "is a" in str(e).lower()


# =============================================================================
# Compatibility Tests
# =============================================================================


def test_works_with_string_path():
    """测试与字符串路径兼容"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = str(Path(tmpdir) / "test.txt")

        connect.put_object(b"data", file_path)
        data = connect.get_object(file_path)

        assert data == b"data"


def test_works_with_pathlib_path():
    """测试与 pathlib.Path 兼容"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        connect.put_object(b"data", file_path)
        data = connect.get_object(file_path)

        assert data == b"data"


def test_mixed_path_types():
    """测试混合使用路径类型"""
    with tempfile.TemporaryDirectory() as tmpdir:
        connect = MacOSConnect()
        file_path = Path(tmpdir) / "test.txt"

        # Write with Path object
        connect.put_object(b"data", file_path)

        # Read with string
        data = connect.get_object(str(file_path))

        assert data == b"data"
