"""MTProto user account methods (telegram_service).

Uses `self._tg_client` to interact with Telegram via MTProto
through the proxy service. Request-building helpers are extracted
so sync and async wrappers stay minimal.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from ._helpers import _sync_request, _async_request
from ._types import ChannelMessage, MTProtoMessage, MTProtoUserInfo

if TYPE_CHECKING:
    import httpx


# ── Request builders ─────────────────────────────────────────────────────────

def _send_message_kwargs(account: str, entity: str, message: str,
                         parse_mode: str | None) -> dict:
    """Build kwargs for account_send_message."""
    payload: dict = {"entity": entity, "message": message}
    if parse_mode:
        payload["parse_mode"] = parse_mode
    return {"method": "POST", "path": f"/v1/mtproto/{account}/send_message", "json": payload}


def _me_kwargs(account: str) -> dict:
    return {"method": "GET", "path": f"/v1/mtproto/{account}/me"}


def _messages_kwargs(account: str, entity: str, limit: int) -> dict:
    return {"method": "GET", "path": f"/v1/mtproto/{account}/messages",
            "params": {"entity": entity, "limit": limit}}


def _poll_messages_kwargs(account: str, entity: str, min_id: int, limit: int) -> dict:
    return {"method": "GET", "path": f"/v1/mtproto/{account}/poll_messages",
            "params": {"entity": entity, "min_id": min_id, "limit": limit}}


def _dialogs_kwargs(account: str, limit: int, type_filter: str | None) -> dict:
    params: dict = {"limit": limit}
    if type_filter:
        params["type_filter"] = type_filter
    return {"method": "GET", "path": f"/v1/mtproto/{account}/dialogs", "params": params}


def _resolve_kwargs(account: str, entity: str) -> dict:
    return {"method": "GET", "path": f"/v1/mtproto/{account}/resolve",
            "params": {"entity": entity}}


def _join_kwargs(account: str, entity: str) -> dict:
    return {"method": "POST", "path": f"/v1/mtproto/{account}/join",
            "json": {"entity": entity}}


def _join_channel_kwargs(account: str, channel: str) -> dict:
    return {"method": "POST", "path": f"/v1/mtproto/{account}/join_channel",
            "json": {"channel": channel}}


# ── Sync mixin ───────────────────────────────────────────────────────────────

class MTProtoMixin:
    """Sync MTProto methods — mixed into TelegramResource."""

    _tg_client: httpx.Client

    def account_send_message(
        self, account: str, entity: str, message: str, *,
        parse_mode: str | None = None,
    ) -> MTProtoMessage:
        """Send a message as a real Telegram user (MTProto).

        Args:
            account: Account alias (registered via dashboard).
            entity: Recipient — "me", "@username", phone "+82...", or chat_id.
            message: Message text.
            parse_mode: Optional parse mode ("html", "md").

        Example:
            sdk.telegram.account_send_message("main", "@friend", "Привет!")
            sdk.telegram.account_send_message("main", "me", "Note to self")
        """
        kw = _send_message_kwargs(account, entity, message, parse_mode)
        return MTProtoMessage.model_validate(
            _sync_request(self._tg_client, **kw)
        )

    def account_me(self, account: str) -> MTProtoUserInfo:
        """Get account info (MTProto)."""
        return MTProtoUserInfo.model_validate(
            _sync_request(self._tg_client, **_me_kwargs(account))
        )

    def account_messages(
        self, account: str, entity: str, limit: int = 20,
    ) -> list[ChannelMessage]:
        """Read messages from a chat (MTProto).

        Args:
            account: Account alias.
            entity: Chat — "me", "@username", chat_id.
            limit: Max messages to return.
        """
        data = _sync_request(self._tg_client, **_messages_kwargs(account, entity, limit))
        return [ChannelMessage.model_validate(m) for m in data]

    def account_poll_messages(
        self, account: str, entity: str, min_id: int = 0, limit: int = 50,
    ) -> list[ChannelMessage]:
        """Poll new messages from a chat/channel since min_id (MTProto).

        Returns messages with id > min_id, sorted oldest-first.
        Use the last message_id as next min_id to get only new messages.

        Args:
            account: Account alias.
            entity: Chat — "@channel_username", chat_id, etc.
            min_id: Only return messages newer than this id.
            limit: Max messages to return.
        """
        data = _sync_request(
            self._tg_client, **_poll_messages_kwargs(account, entity, min_id, limit)
        )
        return [ChannelMessage.model_validate(m) for m in data]

    def account_dialogs(
        self, account: str, limit: int = 100, type_filter: str | None = None,
    ) -> list[dict]:
        """List channels, groups, and chats the account is in (MTProto).

        Args:
            account: Account alias.
            limit: Max dialogs (default 100, max 500).
            type_filter: Optional — "channel", "group", "user".
        """
        return _sync_request(
            self._tg_client, **_dialogs_kwargs(account, limit, type_filter)
        )

    def account_resolve(self, account: str, entity: str) -> dict:
        """Resolve @username or chat_id to entity info (MTProto)."""
        return _sync_request(
            self._tg_client, **_resolve_kwargs(account, entity)
        )

    def account_join(self, account: str, entity: str) -> dict:
        """Join a channel/group by @username or invite link (MTProto).

        Args:
            account: Account alias.
            entity: "@username" or "https://t.me/+xxx" invite link.
        """
        return _sync_request(self._tg_client, **_join_kwargs(account, entity))

    def account_join_channel(self, account: str, channel: str) -> dict:
        """Join a channel or group by invite link (MTProto). Deprecated: use account_join()."""
        return _sync_request(self._tg_client, **_join_channel_kwargs(account, channel))


# ── Async mixin ──────────────────────────────────────────────────────────────

class AsyncMTProtoMixin:
    """Async MTProto methods — mixed into AsyncTelegramResource."""

    _tg_client: httpx.AsyncClient

    async def account_send_message(
        self, account: str, entity: str, message: str, *,
        parse_mode: str | None = None,
    ) -> MTProtoMessage:
        """Send a message as a real Telegram user (MTProto).

        Args:
            account: Account alias (registered via dashboard).
            entity: Recipient — "me", "@username", phone "+82...", or chat_id.
            message: Message text.
            parse_mode: Optional parse mode ("html", "md").

        Example:
            await sdk.telegram.account_send_message("main", "@friend", "Привет!")
            await sdk.telegram.account_send_message("main", "me", "Note to self")
        """
        kw = _send_message_kwargs(account, entity, message, parse_mode)
        return MTProtoMessage.model_validate(
            await _async_request(self._tg_client, **kw)
        )

    async def account_me(self, account: str) -> MTProtoUserInfo:
        """Get account info (MTProto)."""
        return MTProtoUserInfo.model_validate(
            await _async_request(self._tg_client, **_me_kwargs(account))
        )

    async def account_messages(self, account: str, entity: str, limit: int = 20) -> list[ChannelMessage]:
        """Read messages from a chat (MTProto).

        Args:
            account: Account alias.
            entity: Chat — "me", "@username", chat_id.
            limit: Max messages to return.
        """
        data = await _async_request(
            self._tg_client, **_messages_kwargs(account, entity, limit),
        )
        return [ChannelMessage.model_validate(m) for m in data]

    async def account_poll_messages(
        self, account: str, entity: str, min_id: int = 0, limit: int = 50,
    ) -> list[ChannelMessage]:
        """Poll new messages from a chat/channel since min_id (MTProto).

        Returns messages with id > min_id, sorted oldest-first.
        Use the last message_id as next min_id to get only new messages.

        Args:
            account: Account alias.
            entity: Chat — "@channel_username", chat_id, etc.
            min_id: Only return messages newer than this id.
            limit: Max messages to return.
        """
        data = await _async_request(
            self._tg_client, **_poll_messages_kwargs(account, entity, min_id, limit),
        )
        return [ChannelMessage.model_validate(m) for m in data]

    async def account_dialogs(
        self, account: str, limit: int = 100, type_filter: str | None = None,
    ) -> list[dict]:
        """List channels, groups, and chats the account is in (MTProto).

        Args:
            account: Account alias.
            limit: Max dialogs (default 100, max 500).
            type_filter: Optional — "channel", "group", "user".
        """
        return await _async_request(
            self._tg_client, **_dialogs_kwargs(account, limit, type_filter),
        )

    async def account_resolve(self, account: str, entity: str) -> dict:
        """Resolve @username or chat_id to entity info (MTProto)."""
        return await _async_request(
            self._tg_client, **_resolve_kwargs(account, entity),
        )

    async def account_join(self, account: str, entity: str) -> dict:
        """Join a channel/group by @username or invite link (MTProto).

        Args:
            account: Account alias.
            entity: "@username" or "https://t.me/+xxx" invite link.
        """
        return await _async_request(self._tg_client, **_join_kwargs(account, entity))

    async def account_join_channel(self, account: str, channel: str) -> dict:
        """Join a channel or group by invite link (MTProto). Deprecated: use account_join()."""
        return await _async_request(self._tg_client, **_join_channel_kwargs(account, channel))
