"""YakPanel - Web Terminal API (WebSocket)"""
import asyncio
import os
import sys
from fastapi import APIRouter, WebSocket, WebSocketDisconnect

router = APIRouter(prefix="/terminal", tags=["terminal"])


@router.websocket("/ws")
async def terminal_websocket(websocket: WebSocket):
    """WebSocket terminal - spawns shell and streams I/O"""
    await websocket.accept()

    token = websocket.query_params.get("token")
    if token:
        from app.core.security import decode_token
        if not decode_token(token):
            await websocket.close(code=4001)
            return

    if sys.platform == "win32":
        proc = await asyncio.create_subprocess_shell(
            "cmd.exe",
            stdin=asyncio.subprocess.PIPE,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.STDOUT,
        )
    else:
        proc = await asyncio.create_subprocess_shell(
            "/bin/bash",
            stdin=asyncio.subprocess.PIPE,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.STDOUT,
            env={**os.environ, "TERM": "xterm-256color"},
        )

    async def read_stdout():
        try:
            while proc.returncode is None and proc.stdout:
                data = await proc.stdout.read(4096)
                if data:
                    await websocket.send_text(data.decode("utf-8", errors="replace"))
        except (WebSocketDisconnect, ConnectionResetError):
            pass
        finally:
            try:
                proc.kill()
            except ProcessLookupError:
                pass

    async def read_websocket():
        try:
            while True:
                msg = await websocket.receive()
                data = msg.get("text") or (msg.get("bytes") or b"").decode("utf-8", errors="replace")
                if data and proc.stdin and not proc.stdin.is_closing():
                    proc.stdin.write(data.encode("utf-8"))
                    await proc.stdin.drain()
        except (WebSocketDisconnect, ConnectionResetError):
            pass
        finally:
            try:
                proc.kill()
            except ProcessLookupError:
                pass

    await asyncio.gather(read_stdout(), read_websocket())
