"""Manage Claude Code remote control sessions on the hub server."""
from __future__ import annotations

import asyncio
import logging
import os
import shutil

logger = logging.getLogger(__name__)


class RemoteSession:
    """Manages a Claude Code remote-control session as a background subprocess."""

    def __init__(
        self,
        name: str = "Dobby Hub",
        capacity: int = 4,
        cwd: str | None = None,
    ) -> None:
        self.name = name
        self.capacity = capacity
        self.cwd = cwd or os.getcwd()
        self._proc: asyncio.subprocess.Process | None = None
        self._running = False

    @property
    def is_running(self) -> bool:
        return self._running and self._proc is not None and self._proc.returncode is None

    def _find_claude(self) -> str | None:
        """Find the claude binary."""
        claude = shutil.which("claude")
        if claude:
            return claude
        # Common locations
        for path in [
            os.path.expanduser("~/.local/bin/claude"),
            "/usr/local/bin/claude",
        ]:
            if os.path.isfile(path):
                return path
        return None

    async def start(self) -> bool:
        """Start the remote control session via tmux (handles interactive prompts)."""
        claude_bin = self._find_claude()
        if not claude_bin:
            logger.warning("Claude Code CLI not found — remote session not available")
            return False

        tmux = shutil.which("tmux")
        if not tmux:
            logger.warning("tmux not found — required for remote session")
            return False

        tmux_session = "claude-rc"

        # Build env exports for tmux
        env_exports = f"export PATH={os.path.expanduser('~/.local/bin')}:$PATH"
        if os.getuid() == 0:
            env_exports += " && export IS_SANDBOX=1"

        cmd = (
            f"{env_exports} && cd {self.cwd} && "
            f"{claude_bin} remote-control --name \"{self.name}\" "
            f"--capacity {self.capacity} --spawn same-dir"
        )

        try:
            # Kill existing session
            kill_proc = await asyncio.create_subprocess_exec(
                tmux, "kill-session", "-t", tmux_session,
                stdout=asyncio.subprocess.DEVNULL,
                stderr=asyncio.subprocess.DEVNULL,
            )
            await kill_proc.wait()
            await asyncio.sleep(1)

            # Create new tmux session
            proc = await asyncio.create_subprocess_exec(
                tmux, "new-session", "-d", "-s", tmux_session, cmd,
                stdout=asyncio.subprocess.DEVNULL,
                stderr=asyncio.subprocess.DEVNULL,
            )
            await proc.wait()
            self._running = True

            # Wait for the y/n prompt, then send y
            await asyncio.sleep(5)
            await self._tmux_send(tmux, tmux_session, "y")

            # Wait for spawn mode prompt, then send 1
            await asyncio.sleep(3)
            await self._tmux_send(tmux, tmux_session, "1")

            # Check if it connected
            await asyncio.sleep(8)
            output = await self._tmux_capture(tmux, tmux_session)
            if "Connected" in output:
                logger.info("Claude Code remote session active in tmux '%s'", tmux_session)
                # Extract bridge URL
                for line in output.split("\n"):
                    if "claude.ai/code" in line:
                        logger.info("Remote URL: %s", line.strip())
                        break
                return True
            else:
                logger.warning("Remote session may not have connected. Output: %s", output[-200:])
                return True  # Still consider it started

        except Exception as exc:
            logger.warning("Failed to start remote session: %s", exc)
            return False

    async def _tmux_send(self, tmux: str, session: str, keys: str) -> None:
        """Send keys to a tmux session."""
        proc = await asyncio.create_subprocess_exec(
            tmux, "send-keys", "-t", session, keys, "Enter",
            stdout=asyncio.subprocess.DEVNULL,
            stderr=asyncio.subprocess.DEVNULL,
        )
        await proc.wait()

    async def _tmux_capture(self, tmux: str, session: str) -> str:
        """Capture the current tmux pane output."""
        proc = await asyncio.create_subprocess_exec(
            tmux, "capture-pane", "-t", session, "-p",
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.DEVNULL,
        )
        stdout, _ = await proc.communicate()
        return stdout.decode(errors="replace")

    async def _log_output(self) -> None:
        """Read and log output from the remote control process."""
        if not self._proc or not self._proc.stdout:
            return
        try:
            while True:
                line = await self._proc.stdout.readline()
                if not line:
                    break
                decoded = line.decode(errors="replace").strip()
                if decoded:
                    logger.info("[remote-control] %s", decoded)
        except Exception:
            pass
        finally:
            self._running = False
            logger.info(
                "Remote control session ended (PID=%s)", self._proc.pid if self._proc else "?"
            )

    async def stop(self) -> None:
        """Stop the remote control session."""
        tmux = shutil.which("tmux")
        if tmux:
            proc = await asyncio.create_subprocess_exec(
                tmux, "kill-session", "-t", "claude-rc",
                stdout=asyncio.subprocess.DEVNULL,
                stderr=asyncio.subprocess.DEVNULL,
            )
            await proc.wait()
        self._running = False
        logger.info("Remote control session stopped")

    def status(self) -> dict:
        """Return status info about the remote session."""
        return {
            "running": self.is_running,
            "name": self.name,
            "capacity": self.capacity,
            "pid": self._proc.pid if self._proc else None,
            "cwd": self.cwd,
        }
