"""Gmail API service wrapper."""

from __future__ import annotations

import base64
from email.mime.text import MIMEText
from typing import Any, Optional

from googleapiclient.discovery import build

from ..auth.oauth import get_credentials, resolve_profile


def _get_service(profile: Optional[str] = None):
    return build("gmail", "v1", credentials=get_credentials(resolve_profile(profile)))


def _extract_headers(msg: dict) -> dict[str, str]:
    headers: dict[str, str] = {}
    for h in msg.get("payload", {}).get("headers", []):
        if h.get("name") in ("From", "To", "Subject", "Date", "Cc", "Bcc", "Message-ID"):
            headers[h["name"]] = h["value"]
    return headers


def _extract_body(payload: dict) -> str:
    if payload.get("mimeType") == "text/plain" and payload.get("body", {}).get("data"):
        return base64.urlsafe_b64decode(payload["body"]["data"]).decode("utf-8", errors="replace")
    parts = payload.get("parts", [])
    return "\n".join(_extract_body(p) for p in parts)


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------

def search(
    query: str,
    profile: Optional[str] = None,
    max_results: int = 20,
    page_token: Optional[str] = None,
) -> dict[str, Any]:
    svc = _get_service(profile)
    res = svc.users().messages().list(
        userId="me", q=query, maxResults=max_results, pageToken=page_token
    ).execute()

    messages = []
    for m in res.get("messages", []):
        msg = svc.users().messages().get(
            userId="me", id=m["id"], format="metadata",
            metadataHeaders=["From", "To", "Subject", "Date"],
        ).execute()
        headers = _extract_headers(msg)
        messages.append({
            "id": msg["id"],
            "threadId": msg["threadId"],
            "snippet": msg.get("snippet", ""),
            "from": headers.get("From", ""),
            "to": headers.get("To", ""),
            "subject": headers.get("Subject", ""),
            "date": headers.get("Date", ""),
            "labelIds": msg.get("labelIds", []),
        })

    return {
        "resultSizeEstimate": res.get("resultSizeEstimate", 0),
        "nextPageToken": res.get("nextPageToken"),
        "messages": messages,
    }


def read_message(message_id: str, profile: Optional[str] = None) -> dict[str, Any]:
    svc = _get_service(profile)
    msg = svc.users().messages().get(userId="me", id=message_id, format="full").execute()
    headers = _extract_headers(msg)
    body = _extract_body(msg.get("payload", {}))

    attachments = []
    for part in msg.get("payload", {}).get("parts", []):
        if part.get("filename") and part.get("body", {}).get("attachmentId"):
            attachments.append({
                "filename": part["filename"],
                "mimeType": part.get("mimeType"),
                "size": part["body"].get("size"),
                "attachmentId": part["body"]["attachmentId"],
            })

    return {
        "id": msg["id"],
        "threadId": msg["threadId"],
        "from": headers.get("From", ""),
        "to": headers.get("To", ""),
        "subject": headers.get("Subject", ""),
        "date": headers.get("Date", ""),
        "body": body,
        "attachments": attachments,
        "labelIds": msg.get("labelIds", []),
    }


def read_thread(thread_id: str, profile: Optional[str] = None) -> list[dict[str, Any]]:
    svc = _get_service(profile)
    thread = svc.users().threads().get(userId="me", id=thread_id, format="full").execute()
    messages = []
    for msg in thread.get("messages", []):
        headers = _extract_headers(msg)
        messages.append({
            "id": msg["id"],
            "from": headers.get("From", ""),
            "to": headers.get("To", ""),
            "subject": headers.get("Subject", ""),
            "date": headers.get("Date", ""),
            "body": _extract_body(msg.get("payload", {})),
        })
    return messages


def send_message(
    to: str,
    subject: str,
    body: str,
    profile: Optional[str] = None,
    cc: Optional[str] = None,
    bcc: Optional[str] = None,
    in_reply_to: Optional[str] = None,
    thread_id: Optional[str] = None,
) -> dict[str, Any]:
    svc = _get_service(profile)
    msg = MIMEText(body)
    msg["To"] = to
    msg["Subject"] = subject
    if cc:
        msg["Cc"] = cc
    if bcc:
        msg["Bcc"] = bcc
    if in_reply_to:
        msg["In-Reply-To"] = in_reply_to
        msg["References"] = in_reply_to

    raw = base64.urlsafe_b64encode(msg.as_bytes()).decode("ascii")
    send_body: dict[str, Any] = {"raw": raw}
    if thread_id:
        send_body["threadId"] = thread_id

    res = svc.users().messages().send(userId="me", body=send_body).execute()
    return {"messageId": res["id"], "threadId": res.get("threadId", ""), "status": "sent"}


def get_attachment(
    message_id: str,
    attachment_id: str,
    profile: Optional[str] = None,
    save_path: Optional[str] = None,
) -> dict[str, Any]:
    svc = _get_service(profile)
    res = svc.users().messages().attachments().get(
        userId="me", messageId=message_id, id=attachment_id
    ).execute()
    data = res["data"]
    if save_path:
        import pathlib
        pathlib.Path(save_path).write_bytes(base64.urlsafe_b64decode(data))
        return {"saved": save_path, "size": res.get("size")}
    return {"data_preview": data[:200] + "...", "size": res.get("size")}
