from __future__ import annotations

from pathlib import Path
from typing import Any, Union

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


class MacOSConnect(ConnectLike):
    """
    描述:
    - macOS 本地文件系统连接实现类。
    - 实现了 ConnectLike 协议，用于与本地文件系统进行交互。
    - 支持读取和写入本地文件。
    - 自动处理路径解析、用户目录展开和父目录创建。
    - 适用于 macOS 和其他 Unix-like 系统。

    属性:
    - kind: 连接类型标识，固定为 "macos"。

    例子:
    ```python
        from xfintech.connect.instance.macos import MacOSConnect

        connect = MacOSConnect()

        # 写入数据到本地文件
        ref = connect.put_object(b"data", "/path/to/file.txt")

        # 读取本地文件
        data = connect.get_object("/path/to/file.txt")

        # 使用 Path 对象
        from pathlib import Path
        ref = connect.put_object(b"data", Path("~/data/file.txt"))

        # 支持用户目录展开
        data = connect.get_object("~/documents/data.bin")
    ```
    """

    def __init__(self) -> None:
        self.kind: str = "macos"

    def _resolve_path(
        self,
        location: Union[str, Path],
    ) -> Path:
        if location is None:
            msg = "location cannot be None"
            raise ConnectKeyError(msg)
        if isinstance(location, Path):
            location = location
        else:
            location = Path(location)
        location = location.expanduser().resolve(strict=False)
        location.parent.mkdir(
            parents=True,
            exist_ok=True,
        )
        return location

    def __str__(self) -> str:
        return f"{self.__class__.__name__}"

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}()"

    def put_bytes(
        self,
        data: bytes,
        location: Union[str, Path],
        **kwargs: Any,
    ) -> None:
        path = self._resolve_path(location)
        try:
            with path.open("wb") as f:
                f.write(data)
        except Exception as e:
            raise ConnectFailedError(str(e)) from e

    def get_bytes(
        self,
        location: Union[str, Path],
        **kwargs: Any,
    ) -> bytes:
        path = self._resolve_path(location)
        try:
            with path.open("rb") as f:
                data = f.read()
            return data
        except Exception as e:
            raise ConnectFailedError(str(e)) from e

    def get_object(
        self,
        location: str,
        **kwargs: Any,
    ) -> bytes:
        return self.get_bytes(
            location,
            **kwargs,
        )

    def put_object(
        self,
        data: bytes,
        location: str,
        **kwargs: Any,
    ) -> ConnectRef:
        self.put_bytes(
            data,
            location,
            **kwargs,
        )
        return ConnectRef(
            location=str(location),
            kind=self.kind,
        )
