from argparse import Namespace
from datetime import UTC, datetime
from pathlib import Path
from typing import override

import pytest

from home_agent.cli.main import _handle_test
from home_agent.contracts.types import Item, ItemKind
from home_agent.core.config import (
    AlertsConfig,
    AppConfig,
    BudgetConfig,
    LLMConfig,
    MemoryConfig,
    PollConfig,
    RetentionConfig,
)


def _config(db_path: Path) -> AppConfig:
    return AppConfig(
        poll=PollConfig(),
        budget=BudgetConfig(),
        retention=RetentionConfig(),
        alerts=AlertsConfig(),
        llm=LLMConfig(),
        memory=MemoryConfig(),
        enabled_providers=["gmail", "google_calendar"],
        sqlite_path=db_path,
        daily_digest_enabled=True,
    )


class FakeMailReader:
    def list_recent(self) -> list[Item]:
        return [
            Item(
                provider="gmail",
                external_id="msg-1",
                kind=ItemKind.EMAIL,
                received_at=datetime(2026, 3, 2, 10, 0, tzinfo=UTC),
                subject="Invoice ready",
                sender="billing@example.com",
                metadata={"snippet": "Your invoice is ready"},
            )
        ]


class FakeCalendarReader:
    def list_upcoming(self) -> list[Item]:
        return [
            Item(
                provider="google_calendar",
                external_id="evt-1",
                kind=ItemKind.CALENDAR_EVENT,
                received_at=datetime(2026, 3, 2, 14, 30, tzinfo=UTC),
                subject="Project sync",
                sender="calendar@example.com",
                metadata={"start_at": "2026-03-02T14:30:00+00:00"},
            )
        ]


class FakeGmailPlugin:
    id: str = "gmail"
    version: str = "0.1.0"

    def get_mail_reader(self) -> FakeMailReader:
        return FakeMailReader()

    def get_calendar_reader(self) -> None:
        return None


class FakeCalendarPlugin:
    id: str = "google_calendar"
    version: str = "0.1.0"

    def get_mail_reader(self) -> None:
        return None

    def get_calendar_reader(self) -> FakeCalendarReader:
        return FakeCalendarReader()


def test_handle_test_google_prints_mail_and_calendar_items(
    capsys: pytest.CaptureFixture[str],
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    monkeypatch.setattr(
        "home_agent.cli.main.load_plugins",
        lambda enabled: [FakeGmailPlugin(), FakeCalendarPlugin()],
    )

    exit_code = _handle_test(_config(tmp_path / "test.db"), Namespace(provider="google"))

    captured = capsys.readouterr()
    assert exit_code == 0
    assert "gmail: 1 item(s)" in captured.out
    assert "google_calendar: 1 item(s)" in captured.out
    assert "Invoice ready" in captured.out
    assert "Project sync" in captured.out


def test_handle_test_google_reports_provider_errors(
    capsys: pytest.CaptureFixture[str],
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    class FailingGmailPlugin(FakeGmailPlugin):
        @override
        def get_mail_reader(self) -> FakeMailReader:
            msg = "bad token"
            raise RuntimeError(msg)

    monkeypatch.setattr(
        "home_agent.cli.main.load_plugins",
        lambda enabled: [FailingGmailPlugin(), FakeCalendarPlugin()],
    )

    exit_code = _handle_test(_config(tmp_path / "test.db"), Namespace(provider="google"))

    captured = capsys.readouterr()
    assert exit_code == 1
    assert "gmail: bad token" in captured.out
    assert "google_calendar: 1 item(s)" in captured.out
