from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path

from home_agent.contracts.types import Alert, Item, ItemKind
from home_agent.core.config import (
    AlertsConfig,
    AppConfig,
    BudgetConfig,
    LLMConfig,
    LoggingConfig,
    MemoryConfig,
    PollConfig,
    RetentionConfig,
)
from home_agent.core.logging import configure_logging, reset_logging
from home_agent.llm.local_fallback import DeterministicFallbackRunner
from home_agent.memory.engine import ScopedMemoryEngine
from home_agent.orchestrator.service import Orchestrator
from home_agent.storage.sqlite_store import SqliteStore


@dataclass
class FakeMailReader:
    def list_recent(self) -> list[Item]:
        return [
            Item(
                provider="fake-mail",
                external_id="x1",
                kind=ItemKind.EMAIL,
                received_at=datetime.now(tz=UTC),
                subject="Urgent university deadline",
                sender="dean@university.edu",
                metadata={},
            )
        ]

    def search(self, query: str) -> list[Item]:
        _ = query
        return []

    def get_message(self, external_id: str) -> Item | None:
        _ = external_id
        return None


@dataclass
class FakePlugin:
    id: str = "fake"
    version: str = "1.0"

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

    def get_calendar_reader(self) -> None:
        return None


@dataclass
class CapturingNotifier:
    alerts: list[Alert]

    def notify(self, alert: Alert) -> None:
        self.alerts.append(alert)


def test_run_once_persists_items_and_alerts(tmp_path: Path) -> None:
    cfg = AppConfig(
        poll=PollConfig(interval_minutes=15),
        budget=BudgetConfig(monthly_cap_usd=100),
        retention=RetentionConfig(days=30),
        alerts=AlertsConfig(auto_launch_terminal=False),
        llm=LLMConfig(),
        memory=MemoryConfig(),
        enabled_providers=["fake"],
        sqlite_path=tmp_path / "agent.db",
        daily_digest_enabled=True,
    )
    notifier = CapturingNotifier(alerts=[])
    orchestrator = Orchestrator(
        config=cfg,
        plugins=[FakePlugin()],
        store=SqliteStore(cfg.sqlite_path),
        llm_runner=DeterministicFallbackRunner(),
        notifier=notifier,
        memory_engine=ScopedMemoryEngine(),
    )

    result = orchestrator.run_once()

    assert result.processed == 1
    assert result.alerted == 1
    assert len(notifier.alerts) == 1


def test_run_once_writes_orchestrator_log_events(tmp_path: Path) -> None:
    cfg = AppConfig(
        poll=PollConfig(interval_minutes=15),
        budget=BudgetConfig(monthly_cap_usd=100),
        retention=RetentionConfig(days=30),
        alerts=AlertsConfig(auto_launch_terminal=False),
        llm=LLMConfig(),
        memory=MemoryConfig(),
        enabled_providers=["fake"],
        sqlite_path=tmp_path / "agent.db",
        daily_digest_enabled=True,
    )
    configure_logging(
        LoggingConfig(
            directory=tmp_path / "logs",
            file_name="home-agent.jsonl",
            console_level="DEBUG",
            file_level="DEBUG",
            enable_console=False,
        )
    )
    notifier = CapturingNotifier(alerts=[])
    orchestrator = Orchestrator(
        config=cfg,
        plugins=[FakePlugin()],
        store=SqliteStore(cfg.sqlite_path),
        llm_runner=DeterministicFallbackRunner(),
        notifier=notifier,
        memory_engine=ScopedMemoryEngine(),
    )

    orchestrator.run_once()

    log_text = (tmp_path / "logs" / "home-agent.jsonl").read_text(encoding="utf-8")
    assert "orchestrator.run.start" in log_text
    assert "orchestrator.plugin.collection.completed" in log_text
    assert "orchestrator.item.processed" in log_text
    assert '"run_id":' in log_text

    reset_logging()
