"""Tests for calendar REST API routes (U2)."""

from __future__ import annotations

import asyncio
import uuid
from pathlib import Path
from typing import Any

import aiosqlite
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

from agentkit.calendar.db import init_calendar_db
from agentkit.calendar.service import CalendarService
from agentkit.server.auth.dependencies import require_authenticated
from agentkit.server.auth.models import init_auth_db
from agentkit.server.routes import calendar as calendar_routes


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------


TEST_USER_ID = "test-user-id"
TEST_USER_EMAIL = "testuser@example.com"


def _make_test_user() -> dict[str, Any]:
    return {
        "user_id": TEST_USER_ID,
        "username": "testuser",
        "role": "member",
    }


async def _seed_auth_user(auth_db_path: Path) -> None:
    """Seed the test user into the auth DB so get_user_email works."""
    async with aiosqlite.connect(str(auth_db_path)) as db:
        await db.execute(
            "INSERT INTO users (id, username, email, password_hash, role, is_active, "
            "is_terminal_authorized, is_server_terminal_authorized, created_at, updated_at) "
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
            (
                TEST_USER_ID,
                "testuser",
                TEST_USER_EMAIL,
                "fake-hash",
                "member",
                1,
                0,
                0,
                "2026-01-01T00:00:00+00:00",
                "2026-01-01T00:00:00+00:00",
            ),
        )
        await db.commit()


async def _seed_searchable_users(auth_db_path: Path) -> None:
    """Seed extra users for search tests."""
    for name in ("alice", "bob", "charlie"):
        async with aiosqlite.connect(str(auth_db_path)) as db:
            await db.execute(
                "INSERT INTO users (id, username, email, password_hash, role, is_active, "
                "is_terminal_authorized, is_server_terminal_authorized, created_at, updated_at) "
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                (
                    uuid.uuid4().hex,
                    name,
                    f"{name}@example.com",
                    "fake-hash",
                    "member",
                    1,
                    0,
                    0,
                    "2026-01-01T00:00:00+00:00",
                    "2026-01-01T00:00:00+00:00",
                ),
            )
            await db.commit()


@pytest.fixture
def calendar_db_path(tmp_path: Path) -> Path:
    path = tmp_path / "test_calendar.db"
    asyncio.run(init_calendar_db(path))
    return path


@pytest.fixture
def auth_db_path(tmp_path: Path) -> Path:
    path = tmp_path / "test_auth.db"
    asyncio.run(init_auth_db(path))
    asyncio.run(_seed_auth_user(path))
    return path


@pytest.fixture
def app(calendar_db_path: Path, auth_db_path: Path) -> FastAPI:
    """Create a test app with CalendarService and mock auth."""
    service = CalendarService(db_path=calendar_db_path, auth_db_path=auth_db_path)

    app = FastAPI()
    app.state.calendar_service = service
    app.state.auth_db_path = str(auth_db_path)
    app.include_router(calendar_routes.router, prefix="/api/v1")

    # Override auth dependency to return a test user
    app.dependency_overrides[require_authenticated] = lambda: _make_test_user()
    return app


@pytest.fixture
def client(app: FastAPI) -> TestClient:
    return TestClient(app)


@pytest.fixture
def unauth_app(calendar_db_path: Path, auth_db_path: Path) -> FastAPI:
    """App without auth override — simulates unauthenticated requests."""
    service = CalendarService(db_path=calendar_db_path, auth_db_path=auth_db_path)
    app = FastAPI()
    app.state.calendar_service = service
    app.state.auth_db_path = str(auth_db_path)
    app.include_router(calendar_routes.router, prefix="/api/v1")
    # No dependency override → require_authenticated will see no current_user
    return app


@pytest.fixture
def unauth_client(unauth_app: FastAPI) -> TestClient:
    return TestClient(unauth_app)


# ---------------------------------------------------------------------------
# Auth requirement
# ---------------------------------------------------------------------------


def test_route_create_event_requires_auth(unauth_client: TestClient) -> None:
    """No auth → 401."""
    resp = unauth_client.post(
        "/api/v1/calendar/events",
        json={
            "title": "Test",
            "start_time": "2026-07-01T10:00:00+00:00",
            "end_time": "2026-07-01T11:00:00+00:00",
        },
    )
    assert resp.status_code == 401


# ---------------------------------------------------------------------------
# Create event
# ---------------------------------------------------------------------------


def test_route_create_event_success(client: TestClient) -> None:
    """Create event via API returns 200 with event data."""
    resp = client.post(
        "/api/v1/calendar/events",
        json={
            "title": "Sprint Planning",
            "start_time": "2026-07-01T10:00:00+00:00",
            "end_time": "2026-07-01T11:00:00+00:00",
            "description": "Bi-weekly sprint planning",
            "location": "Room A",
        },
    )
    assert resp.status_code == 200
    data = resp.json()
    assert data["success"] is True
    event = data["event"]
    assert event["title"] == "Sprint Planning"
    assert event["start_time"] == "2026-07-01T10:00:00+00:00"
    assert event["description"] == "Bi-weekly sprint planning"
    assert event["location"] == "Room A"
    assert event["source"] == "manual"
    assert "id" in event


# ---------------------------------------------------------------------------
# List events
# ---------------------------------------------------------------------------


def test_route_list_events_returns_events(client: TestClient) -> None:
    """Create events, list via API returns them."""
    for i in range(3):
        client.post(
            "/api/v1/calendar/events",
            json={
                "title": f"Event {i}",
                "start_time": f"2026-07-{i + 1:02d}T10:00:00+00:00",
                "end_time": f"2026-07-{i + 1:02d}T11:00:00+00:00",
            },
        )

    resp = client.get("/api/v1/calendar/events")
    assert resp.status_code == 200
    data = resp.json()
    assert data["success"] is True
    assert data["count"] == 3
    titles = {e["title"] for e in data["events"]}
    assert titles == {"Event 0", "Event 1", "Event 2"}


# ---------------------------------------------------------------------------
# Tag filter via API (G2)
# ---------------------------------------------------------------------------


def test_route_list_events_filters_by_tag(client: TestClient) -> None:
    """G2 tag filter via API — only tagged events returned."""
    # Create a tag first
    tag_resp = client.post("/api/v1/calendar/tags", json={"name": "important"})
    assert tag_resp.status_code == 200
    tag_id = tag_resp.json()["tag"]["id"]

    # Event 1: with tag
    client.post(
        "/api/v1/calendar/events",
        json={
            "title": "Tagged Event",
            "start_time": "2026-07-01T10:00:00+00:00",
            "end_time": "2026-07-01T11:00:00+00:00",
            "tag_ids": [tag_id],
        },
    )

    # Event 2: without tag
    client.post(
        "/api/v1/calendar/events",
        json={
            "title": "Untagged Event",
            "start_time": "2026-07-02T10:00:00+00:00",
            "end_time": "2026-07-02T11:00:00+00:00",
        },
    )

    # List with tag filter
    resp = client.get("/api/v1/calendar/events", params={"tag_id": tag_id})
    assert resp.status_code == 200
    data = resp.json()
    assert data["count"] == 1
    assert data["events"][0]["title"] == "Tagged Event"


# ---------------------------------------------------------------------------
# User search via API (G5)
# ---------------------------------------------------------------------------


def test_route_search_users(client: TestClient, auth_db_path: Path) -> None:
    """G5 user search via API returns matching users."""
    asyncio.run(_seed_searchable_users(auth_db_path))

    resp = client.get("/api/v1/calendar/users/search", params={"q": "ali"})
    assert resp.status_code == 200
    data = resp.json()
    assert data["success"] is True
    assert data["count"] == 1
    assert data["users"][0]["username"] == "alice"
    assert data["users"][0]["email"] == "alice@example.com"
    # Must not expose sensitive fields
    assert "id" not in data["users"][0]
    assert "password_hash" not in data["users"][0]
