from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, cast

from googleapiclient.discovery import build

from home_agent.auth.google_auth import GoogleAuthManager
from home_agent.auth.token_store import EncryptedTokenStore
from home_agent.contracts.protocols import CalendarReader
from home_agent.contracts.types import Item, ItemKind
from home_agent.plugins_builtin._google_api_types import CalendarService

CALENDAR_SCOPES = ("https://www.googleapis.com/auth/calendar.readonly",)


@dataclass
class GoogleCalendarReader:
    service: CalendarService

    def list_upcoming(self) -> list[Item]:
        now = datetime.now(tz=UTC).isoformat()
        raw = (
            self.service.events()
            .list(
                calendarId="primary",
                timeMin=now,
                maxResults=25,
                singleEvents=True,
                orderBy="startTime",
            )
            .execute()
        )
        return _extract_items(raw)

    def get_event(self, external_id: str) -> Item | None:
        raw = self.service.events().get(calendarId="primary", eventId=external_id).execute()
        return _to_item(raw)


class GoogleCalendarPlugin:
    id: str = "google_calendar"
    version: str = "0.2.0"

    def __init__(self) -> None:
        self._store: EncryptedTokenStore = EncryptedTokenStore(Path(".data/tokens"))

    def init_auth(self) -> None:
        manager = GoogleAuthManager(self._store, token_name="google")
        manager.init_desktop_auth(CALENDAR_SCOPES)

    def get_mail_reader(self) -> None:
        return None

    def get_calendar_reader(self) -> CalendarReader | None:
        manager = GoogleAuthManager(self._store, token_name="google")
        creds = manager.get_credentials(CALENDAR_SCOPES)
        resource = build("calendar", "v3", credentials=creds, cache_discovery=False)
        service = cast("CalendarService", cast("object", resource))
        return GoogleCalendarReader(service=service)


def _extract_items(raw: dict[str, Any]) -> list[Item]:
    items = raw.get("items", [])
    if not isinstance(items, list):
        return []
    output: list[Item] = []
    for event in items:
        if isinstance(event, dict):
            item = _to_item(event)
            if item is not None:
                output.append(item)
    return output


def _to_item(event: dict[str, Any]) -> Item | None:
    external_id = event.get("id")
    if not isinstance(external_id, str):
        return None

    start_data = event.get("start", {})
    start_raw = None
    if isinstance(start_data, dict):
        date_time = start_data.get("dateTime")
        date_only = start_data.get("date")
        if isinstance(date_time, str):
            start_raw = date_time
        elif isinstance(date_only, str):
            start_raw = f"{date_only}T00:00:00+00:00"
    start_at = _parse_start(start_raw)

    summary = event.get("summary")
    subject = summary if isinstance(summary, str) else "(no title)"

    creator = event.get("creator", {})
    sender = "calendar"
    if isinstance(creator, dict):
        email_val = creator.get("email")
        if isinstance(email_val, str):
            sender = email_val

    return Item(
        provider="google_calendar",
        external_id=external_id,
        kind=ItemKind.CALENDAR_EVENT,
        received_at=start_at,
        subject=subject,
        sender=sender,
        metadata={
            "start_at": start_at.isoformat(),
            "htmlLink": event.get("htmlLink"),
            "status": event.get("status"),
        },
    )


def _parse_start(value: str | None) -> datetime:
    if value is None:
        return datetime.now(tz=UTC)
    normalized = value.replace("Z", "+00:00")
    try:
        parsed = datetime.fromisoformat(normalized)
        if parsed.tzinfo is None:
            return parsed.replace(tzinfo=UTC)
        return parsed.astimezone(UTC)
    except ValueError:
        return datetime.now(tz=UTC)
