"""Base web executor for remote CLI execution"""

import os
from abc import ABC, abstractmethod
from typing import AsyncIterator
from diona.project.cli.engine.result import StreamChunk


class BaseWebExecutor(ABC):
    """Base class for web execution - shared logic for HTTP remote command execution"""

    def __init__(self):
        from diona.project.cli.web.constants import DEFAULT_WEB_ADDR, DEFAULT_WEB_PORT, ENV_WEB_ADDR, ENV_WEB_PORT
        self._web_addr = os.environ.get(ENV_WEB_ADDR, DEFAULT_WEB_ADDR)
        self._web_port = int(os.environ.get(ENV_WEB_PORT, str(DEFAULT_WEB_PORT)))

    @property
    def web_addr(self) -> str:
        return self._web_addr

    @property
    def web_port(self) -> int:
        return self._web_port

    @property
    def url(self) -> str:
        return f"http://{self._web_addr}:{self._web_port}/execute/stream"

    async def execute_remote(self, user_input: str) -> AsyncIterator[StreamChunk]:
        """Execute command on remote server via HTTP"""
        try:
            import aiohttp
            from diona.project.encrypt import get_crypto_manager

            crypto = get_crypto_manager()
            encrypted_command = crypto.encrypt(user_input)

            async with aiohttp.ClientSession() as session:
                async with session.post(
                    self.url,
                    json={"command": encrypted_command},
                    timeout=aiohttp.ClientTimeout(total=60)
                ) as response:
                    if response.status == 200:
                        async for line in response.content:
                            decoded = line.decode("utf-8").strip()
                            if decoded.startswith("data: "):
                                data = decoded[6:]
                                decrypted = crypto.decrypt(data)
                                yield StreamChunk(content=decrypted)
                            elif decoded.startswith("error: "):
                                data = decoded[7:]
                                decrypted = crypto.decrypt(data)
                                yield StreamChunk(content=f"[ERROR] {decrypted}", is_error=True)
                            elif decoded.startswith("done:"):
                                yield StreamChunk(content="", is_final=True)
                    else:
                        yield StreamChunk(
                            content=f"[ERROR] Webserver returned status {response.status}",
                            is_error=True,
                            is_final=True
                        )

        except ImportError:
            yield StreamChunk(
                content="[ERROR] aiohttp library is required for web mode",
                is_error=True,
                is_final=True
            )
        except ConnectionRefusedError:
            yield StreamChunk(
                content=f"[ERROR] Cannot connect to webserver at {self.url}",
                is_error=True,
                is_final=True
            )
        except Exception as e:
            yield StreamChunk(content=f"[ERROR] {str(e)}", is_error=True, is_final=True)

    @abstractmethod
    async def execute(self, user_input: str) -> AsyncIterator[StreamChunk]:
        """Abstract method to implement in subclasses"""
        pass
