"""
Thread resource for managing email threads and labels.
"""

from typing import Any, Dict, List, Optional

from emailr.http import AsyncHttpClient, HttpClient
from emailr.types import (
    Pagination,
    PaginatedResponse,
    SuccessResponse,
    Thread,
    ThreadDetail,
    ThreadDraft,
    ThreadDraftRequest,
    ThreadReplyRequest,
    ThreadReplyResponse,
    UpdateLabelsRequest,
    UpdateLabelsResponse,
    UpdateThreadLabelsResponse,
)


class ThreadsResource:
    """Synchronous thread resource for managing email threads."""

    def __init__(self, http: HttpClient) -> None:
        self._http = http

    def list(
        self,
        *,
        label: Optional[str] = None,
        page: Optional[int] = None,
        limit: Optional[int] = None,
        search: Optional[str] = None,
        inbox_id: Optional[str] = None,
    ) -> PaginatedResponse[Thread]:
        """List email threads with optional filtering."""
        params: Dict[str, Any] = {}
        if label is not None:
            params["label"] = label
        if page is not None:
            params["page"] = str(page)
        if limit is not None:
            params["limit"] = str(limit)
        if search is not None:
            params["search"] = search
        if inbox_id is not None:
            params["inbox_id"] = inbox_id

        data = self._http.get("/v1/threads", params=params)
        return PaginatedResponse(
            data=[Thread.from_dict(t) for t in data.get("data", [])],
            pagination=Pagination(
                page=data["pagination"]["page"],
                limit=data["pagination"]["limit"],
                total=data["pagination"]["total"],
                pages=data["pagination"]["pages"],
            ),
        )

    def get(self, thread_id: str) -> ThreadDetail:
        """Get thread detail with all messages."""
        data = self._http.get(f"/v1/threads/{thread_id}")
        return ThreadDetail.from_dict(data)

    def update_labels(
        self,
        thread_id: str,
        *,
        add: Optional[List[str]] = None,
        remove: Optional[List[str]] = None,
    ) -> UpdateThreadLabelsResponse:
        """Add or remove labels from all emails in a thread."""
        request = UpdateLabelsRequest(add=add, remove=remove)
        data = self._http.patch(f"/v1/threads/{thread_id}/labels", request.to_dict())
        return UpdateThreadLabelsResponse.from_dict(data)

    def update_email_labels(
        self,
        email_id: str,
        *,
        add: Optional[List[str]] = None,
        remove: Optional[List[str]] = None,
    ) -> UpdateLabelsResponse:
        """Add or remove labels from a single email."""
        request = UpdateLabelsRequest(add=add, remove=remove)
        data = self._http.patch(f"/v1/threads/emails/{email_id}/labels", request.to_dict())
        return UpdateLabelsResponse.from_dict(data)

    def reply(
        self,
        thread_id: str,
        *,
        html: Optional[str] = None,
        text: Optional[str] = None,
        to: Optional[str] = None,
        cc: Optional[str] = None,
        bcc: Optional[str] = None,
        from_: Optional[str] = None,
        from_name: Optional[str] = None,
        reply_to_email: Optional[str] = None,
    ) -> ThreadReplyResponse:
        """
        Reply to a thread. All fields except html/text are auto-resolved
        from the thread's inbox when not provided.
        """
        request = ThreadReplyRequest(
            html=html, text=text, to=to, cc=cc, bcc=bcc,
            from_=from_, from_name=from_name, reply_to_email=reply_to_email,
        )
        data = self._http.post(f"/v1/threads/{thread_id}/reply", request.to_dict())
        return ThreadReplyResponse.from_dict(data)

    def save_draft(
        self,
        thread_id: str,
        *,
        html: Optional[str] = None,
        text: Optional[str] = None,
        to: Optional[str] = None,
        cc: Optional[str] = None,
        bcc: Optional[str] = None,
        from_: Optional[str] = None,
        reply_to_email: Optional[str] = None,
    ) -> ThreadDraft:
        """Save or update a draft reply for a thread."""
        request = ThreadDraftRequest(
            html=html, text=text, to=to, cc=cc, bcc=bcc,
            from_=from_, reply_to_email=reply_to_email,
        )
        data = self._http.put(f"/v1/threads/{thread_id}/draft", request.to_dict())
        return ThreadDraft.from_dict(data)

    def get_draft(self, thread_id: str) -> ThreadDraft:
        """Get the saved draft reply for a thread."""
        data = self._http.get(f"/v1/threads/{thread_id}/draft")
        return ThreadDraft.from_dict(data)

    def delete_draft(self, thread_id: str) -> SuccessResponse:
        """Delete the draft reply for a thread."""
        data = self._http.delete(f"/v1/threads/{thread_id}/draft")
        return SuccessResponse(success=data.get("success", True))


class AsyncThreadsResource:
    """Asynchronous thread resource for managing email threads."""

    def __init__(self, http: AsyncHttpClient) -> None:
        self._http = http

    async def list(
        self,
        *,
        label: Optional[str] = None,
        page: Optional[int] = None,
        limit: Optional[int] = None,
        search: Optional[str] = None,
        inbox_id: Optional[str] = None,
    ) -> PaginatedResponse[Thread]:
        """List email threads with optional filtering."""
        params: Dict[str, Any] = {}
        if label is not None:
            params["label"] = label
        if page is not None:
            params["page"] = str(page)
        if limit is not None:
            params["limit"] = str(limit)
        if search is not None:
            params["search"] = search
        if inbox_id is not None:
            params["inbox_id"] = inbox_id

        data = await self._http.get("/v1/threads", params=params)
        return PaginatedResponse(
            data=[Thread.from_dict(t) for t in data.get("data", [])],
            pagination=Pagination(
                page=data["pagination"]["page"],
                limit=data["pagination"]["limit"],
                total=data["pagination"]["total"],
                pages=data["pagination"]["pages"],
            ),
        )

    async def get(self, thread_id: str) -> ThreadDetail:
        """Get thread detail with all messages."""
        data = await self._http.get(f"/v1/threads/{thread_id}")
        return ThreadDetail.from_dict(data)

    async def update_labels(
        self,
        thread_id: str,
        *,
        add: Optional[List[str]] = None,
        remove: Optional[List[str]] = None,
    ) -> UpdateThreadLabelsResponse:
        """Add or remove labels from all emails in a thread."""
        request = UpdateLabelsRequest(add=add, remove=remove)
        data = await self._http.patch(f"/v1/threads/{thread_id}/labels", request.to_dict())
        return UpdateThreadLabelsResponse.from_dict(data)

    async def update_email_labels(
        self,
        email_id: str,
        *,
        add: Optional[List[str]] = None,
        remove: Optional[List[str]] = None,
    ) -> UpdateLabelsResponse:
        """Add or remove labels from a single email."""
        request = UpdateLabelsRequest(add=add, remove=remove)
        data = await self._http.patch(f"/v1/threads/emails/{email_id}/labels", request.to_dict())
        return UpdateLabelsResponse.from_dict(data)

    async def reply(
        self,
        thread_id: str,
        *,
        html: Optional[str] = None,
        text: Optional[str] = None,
        to: Optional[str] = None,
        cc: Optional[str] = None,
        bcc: Optional[str] = None,
        from_: Optional[str] = None,
        from_name: Optional[str] = None,
        reply_to_email: Optional[str] = None,
    ) -> ThreadReplyResponse:
        """Reply to a thread with auto-resolved sender identity."""
        request = ThreadReplyRequest(
            html=html, text=text, to=to, cc=cc, bcc=bcc,
            from_=from_, from_name=from_name, reply_to_email=reply_to_email,
        )
        data = await self._http.post(f"/v1/threads/{thread_id}/reply", request.to_dict())
        return ThreadReplyResponse.from_dict(data)

    async def save_draft(
        self,
        thread_id: str,
        *,
        html: Optional[str] = None,
        text: Optional[str] = None,
        to: Optional[str] = None,
        cc: Optional[str] = None,
        bcc: Optional[str] = None,
        from_: Optional[str] = None,
        reply_to_email: Optional[str] = None,
    ) -> ThreadDraft:
        """Save or update a draft reply for a thread."""
        request = ThreadDraftRequest(
            html=html, text=text, to=to, cc=cc, bcc=bcc,
            from_=from_, reply_to_email=reply_to_email,
        )
        data = await self._http.put(f"/v1/threads/{thread_id}/draft", request.to_dict())
        return ThreadDraft.from_dict(data)

    async def get_draft(self, thread_id: str) -> ThreadDraft:
        """Get the saved draft reply for a thread."""
        data = await self._http.get(f"/v1/threads/{thread_id}/draft")
        return ThreadDraft.from_dict(data)

    async def delete_draft(self, thread_id: str) -> SuccessResponse:
        """Delete the draft reply for a thread."""
        data = await self._http.delete(f"/v1/threads/{thread_id}/draft")
        return SuccessResponse(success=data.get("success", True))
