from __future__ import annotations
from typing import Optional, TYPE_CHECKING

if TYPE_CHECKING:
    from .client import Shadey


class ShadeySession:
    def __init__(self, id: str, cdp_url: str, client: "Shadey"):
        self.id = id
        self.cdp_url = cdp_url
        self._client = client
        self._closed = False

    async def close(self, save: bool = False):
        if not self._closed:
            path = f"/v1/sessions/{self.id}"
            if save:
                path += "?save=true"
            await self._client._request("DELETE", path)
            self._closed = True

    async def __aenter__(self):
        return self

    async def __aexit__(self, *args):
        await self.close()

    # -- behavioral actions --

    async def click(self, x: float, y: float, width: float = 50.0) -> dict:
        return await self._behave({
            "action": "move_and_click",
            "target_x": x,
            "target_y": y,
            "target_width": width,
        })

    async def type_text(self, text: str, context: str = "form") -> dict:
        return await self._behave({
            "action": "type",
            "text": text,
            "typing_context": context,
        })

    async def scroll(self, distance: float) -> dict:
        return await self._behave({
            "action": "scroll",
            "distance": distance,
        })

    async def dwell(self, context: str = "content") -> dict:
        return await self._behave({
            "action": "dwell",
            "page_context": context,
        })

    async def idle(self, duration_ms: int = 5000) -> dict:
        return await self._behave({
            "action": "idle_browse",
            "duration_ms": duration_ms,
        })

    async def _behave(self, payload: dict) -> dict:
        return await self._client._request(
            "POST", f"/v1/sessions/{self.id}/behave", json=payload
        )

    # -- REST actions --

    async def goto(self, url: str, wait_ms: int = 3000) -> dict:
        return await self._client._request(
            "POST", f"/v1/sessions/{self.id}/navigate",
            json={"url": url, "wait_ms": wait_ms},
        )

    async def screenshot(self) -> str:
        data = await self._client._request(
            "POST", f"/v1/sessions/{self.id}/screenshot"
        )
        return data["data"]

    async def extract(self, selector: str, attribute: str = "textContent", all: bool = False) -> dict:
        return await self._client._request(
            "POST", f"/v1/sessions/{self.id}/extract",
            json={"selector": selector, "attribute": attribute, "all": all},
        )

    async def evaluate(self, expression: str) -> dict:
        return await self._client._request(
            "POST", f"/v1/sessions/{self.id}/evaluate",
            json={"expression": expression},
        )

    async def content(self) -> dict:
        return await self._client._request(
            "POST", f"/v1/sessions/{self.id}/content"
        )

    # -- CDP access --

    @property
    def playwright_url(self) -> str:
        return self.cdp_url

    @property
    def puppeteer_url(self) -> str:
        return self.cdp_url

    @property
    def is_active(self) -> bool:
        return not self._closed

    def __repr__(self):
        status = "active" if not self._closed else "closed"
        return f"ShadeySession(id={self.id!r}, status={status!r})"
