"""Tests for multi-project support."""

import pytest

from loom.graph.project import (
    archive_project,
    create_project,
    get_project,
    get_project_status,
    list_projects,
    update_project,
)
from loom.graph import cache, store
from loom.graph.task import Task, TaskStatus


async def test_create_multiple_projects(pool):
    p1 = await create_project(pool, "Project Alpha", "First project")
    p2 = await create_project(pool, "Project Beta", "Second project")
    projects = await list_projects(pool)
    names = {p["name"] for p in projects}
    assert "Project Alpha" in names
    assert "Project Beta" in names


async def test_project_isolation(pool):
    """Tasks in project A are not visible in project B."""
    p1 = await create_project(pool, "Isolated A")
    p2 = await create_project(pool, "Isolated B")
    pid1, pid2 = str(p1["id"]), str(p2["id"])

    t1 = Task(id="iso-001", project_id=pid1, title="Task in A", status=TaskStatus.PENDING)
    t2 = Task(id="iso-002", project_id=pid2, title="Task in B", status=TaskStatus.PENDING)
    await store.create_task(pool, t1)
    await store.create_task(pool, t2)

    ready_a = await store.get_ready_tasks(pool, pid1)
    ready_b = await store.get_ready_tasks(pool, pid2)
    assert all(t.project_id == pid1 for t in ready_a)
    assert all(t.project_id == pid2 for t in ready_b)


async def test_archive_project(pool):
    p = await create_project(pool, "To Archive")
    pid = str(p["id"])
    await archive_project(pool, pid)
    projects = await list_projects(pool)
    assert not any(str(pp["id"]) == pid for pp in projects)
    # But still visible when including archived
    all_projects = await list_projects(pool, include_archived=True)
    assert any(str(pp["id"]) == pid for pp in all_projects)


async def test_update_project(pool):
    p = await create_project(pool, "Update Me")
    pid = str(p["id"])
    updated = await update_project(pool, pid, description="New description")
    assert updated["description"] == "New description"


async def test_cross_project_task_counts(pool):
    p1 = await create_project(pool, "Count A")
    p2 = await create_project(pool, "Count B")
    pid1, pid2 = str(p1["id"]), str(p2["id"])

    for i in range(3):
        t = Task(id=f"cnt-a-{i}", project_id=pid1, title=f"A-{i}", status=TaskStatus.PENDING)
        await store.create_task(pool, t)
    for i in range(5):
        t = Task(id=f"cnt-b-{i}", project_id=pid2, title=f"B-{i}", status=TaskStatus.PENDING)
        await store.create_task(pool, t)

    status_a = await get_project_status(pool, pid1)
    status_b = await get_project_status(pool, pid2)
    assert status_a.total == 3
    assert status_b.total == 5


async def test_list_projects_excludes_archived(pool):
    p1 = await create_project(pool, "Active Project")
    p2 = await create_project(pool, "Archived Project")
    await archive_project(pool, str(p2["id"]))
    active = await list_projects(pool)
    names = {p["name"] for p in active}
    assert "Active Project" in names
    assert "Archived Project" not in names


async def test_cache_project_isolation(pool, redis_conn):
    """Redis cache keys are scoped per project."""
    p1 = await create_project(pool, "Cache A")
    p2 = await create_project(pool, "Cache B")
    pid1, pid2 = str(p1["id"]), str(p2["id"])

    t1 = Task(id="cache-a-1", project_id=pid1, title="Cached A", status=TaskStatus.PENDING)
    t2 = Task(id="cache-b-1", project_id=pid2, title="Cached B", status=TaskStatus.PENDING)
    await store.create_task(pool, t1)
    await store.create_task(pool, t2)

    await cache.sync_task(redis_conn, t1)
    await cache.sync_task(redis_conn, t2)

    # Each project's cache is independent
    task_a = await cache.get_task(redis_conn, pool, pid1, "cache-a-1")
    task_b = await cache.get_task(redis_conn, pool, pid2, "cache-b-1")
    assert task_a.project_id == pid1
    assert task_b.project_id == pid2


async def test_clear_project_cache(pool, redis_conn):
    """Clearing one project's cache doesn't affect another."""
    p1 = await create_project(pool, "Clear A")
    p2 = await create_project(pool, "Clear B")
    pid1, pid2 = str(p1["id"]), str(p2["id"])

    t1 = Task(id="clr-a-1", project_id=pid1, title="Clear A", status=TaskStatus.PENDING)
    t2 = Task(id="clr-b-1", project_id=pid2, title="Clear B", status=TaskStatus.PENDING)
    await store.create_task(pool, t1)
    await store.create_task(pool, t2)
    await cache.sync_task(redis_conn, t1)
    await cache.sync_task(redis_conn, t2)

    await cache.clear_project_cache(redis_conn, pid1)

    # Project B's cache should still work
    task_b = await cache.get_task(redis_conn, pool, pid2, "clr-b-1")
    assert task_b.id == "clr-b-1"
