"""
Platform-specific IPC transport implementation.
"""

import asyncio
import os
import tempfile
from abc import ABC, abstractmethod
from typing import Optional

from airctl.common.platform import Platform, get_platform, is_windows


def get_default_socket_path() -> str:
    """Get the default socket path for the current platform."""
    if is_windows():
        return r"\\.\pipe\airctl-ble"
    else:
        return os.path.join(tempfile.gettempdir(), "airctl-ble.sock")


def get_pid_file_path() -> str:
    """Get the PID file path for daemon process."""
    if is_windows():
        return os.path.join(tempfile.gettempdir(), "airctl-ble.pid")
    else:
        return os.path.join(tempfile.gettempdir(), "airctl-ble.pid")


class IPCTransport(ABC):
    """Abstract base class for IPC transport."""

    @abstractmethod
    async def connect(self) -> None:
        """Connect to the IPC endpoint."""
        pass

    @abstractmethod
    async def disconnect(self) -> None:
        """Disconnect from the IPC endpoint."""
        pass

    @abstractmethod
    async def send(self, data: bytes) -> None:
        """Send data through the transport."""
        pass

    @abstractmethod
    async def receive(self) -> bytes:
        """Receive data from the transport."""
        pass

    @abstractmethod
    def is_connected(self) -> bool:
        """Check if transport is connected."""
        pass


class UnixSocketTransport(IPCTransport):
    """Unix domain socket transport for Linux/macOS."""

    def __init__(self, socket_path: Optional[str] = None):
        self.socket_path = socket_path or get_default_socket_path()
        self._reader: Optional[asyncio.StreamReader] = None
        self._writer: Optional[asyncio.StreamWriter] = None

    async def connect(self) -> None:
        """Connect to Unix socket."""
        self._reader, self._writer = await asyncio.open_unix_connection(self.socket_path)

    async def disconnect(self) -> None:
        """Disconnect from Unix socket."""
        if self._writer:
            self._writer.close()
            await self._writer.wait_closed()
            self._writer = None
            self._reader = None

    async def send(self, data: bytes) -> None:
        """Send data through the socket."""
        if not self._writer:
            raise ConnectionError("Not connected")
        self._writer.write(data)
        await self._writer.drain()

    async def receive(self) -> bytes:
        """Receive a line from the socket."""
        if not self._reader:
            raise ConnectionError("Not connected")
        data = await self._reader.readline()
        return data

    def is_connected(self) -> bool:
        """Check if connected."""
        return self._writer is not None and not self._writer.is_closing()


class WindowsNamedPipeTransport(IPCTransport):
    """Windows named pipe transport."""

    def __init__(self, pipe_name: Optional[str] = None):
        self.pipe_name = pipe_name or get_default_socket_path()
        self._connected = False
        self._buffer = b""
        self._handle = None

    async def connect(self) -> None:
        """Connect to named pipe."""
        import win32file
        import win32pipe

        max_retries = 50
        for retry in range(max_retries):
            try:
                self._handle = win32file.CreateFile(
                    self.pipe_name,
                    win32file.GENERIC_READ | win32file.GENERIC_WRITE,
                    0,
                    None,
                    win32file.OPEN_EXISTING,
                    0,
                    None,
                )
                break
            except Exception as e:
                if retry == max_retries - 1:
                    raise ConnectionError(f"Failed to connect to daemon after {max_retries} retries: {e}")
                await asyncio.sleep(0.1)

        win32pipe.SetNamedPipeHandleState(
            self._handle,
            win32pipe.PIPE_READMODE_BYTE,
            None,
            None,
        )
        self._connected = True

    async def disconnect(self) -> None:
        """Disconnect from named pipe."""
        if self._handle:
            import win32file

            win32file.CloseHandle(self._handle)
            self._handle = None
        self._connected = False

    async def send(self, data: bytes) -> None:
        """Send data through the pipe."""
        if not self._handle:
            raise ConnectionError("Not connected")
        import win32file

        win32file.WriteFile(self._handle, data)

    async def receive(self) -> bytes:
        """Receive a line from the pipe."""
        if not self._handle:
            raise ConnectionError("Not connected")
        import win32file

        while b"\n" not in self._buffer:
            result, data = win32file.ReadFile(self._handle, 4096)
            if result != 0:
                raise ConnectionError(f"Read error: {result}")
            if not data:
                raise ConnectionError("Pipe closed")
            self._buffer += data

        line, self._buffer = self._buffer.split(b"\n", 1)
        return line + b"\n"

    def is_connected(self) -> bool:
        """Check if connected."""
        return self._connected and self._handle is not None


def create_transport(socket_path: Optional[str] = None) -> IPCTransport:
    """Create appropriate transport for the current platform."""
    platform = get_platform()
    
    if platform == Platform.WINDOWS:
        return WindowsNamedPipeTransport(pipe_name=socket_path)
    else:
        return UnixSocketTransport(socket_path=socket_path)
