import pytest
from httpx import AsyncClient, ASGITransport
from project_hub.web.app import create_app

def _make_state(**overrides):
    base = {
        "ready": True, "repos": [], "mrs": [], "pipelines": [],
        "vulns": [], "events": [], "last_refresh": None,
        "sync_status": "idle", "usernames": {},
        "pinned": [], "repo_order": [], "excluded": [],
        "forges": {},
    }
    base.update(overrides)
    return base

@pytest.fixture
def app():
    state = _make_state()
    return create_app(
        get_state=lambda: state,
        trigger_refresh=None,
        dismiss_event=None,
    )

@pytest.fixture
async def client(app):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        yield c

async def test_sync_status_fragment_idle(client):
    resp = await client.get("/fragment/sync-status")
    assert resp.status_code == 200
    assert "Sync" in resp.text
    assert "aria-busy" not in resp.text

async def test_action_sync_returns_204(client):
    resp = await client.post("/action/sync", headers={"HX-Request": "true"})
    assert resp.status_code == 204

async def test_events_page_redirects(client):
    resp = await client.get("/events", follow_redirects=False)
    assert resp.status_code == 301

async def test_events_panel_fragment(client):
    resp = await client.get("/fragment/events-panel")
    assert resp.status_code == 200

async def test_settings_page(client):
    resp = await client.get("/settings")
    assert resp.status_code == 200


async def test_repo_page_found(client):
    """Repo page renders for a known repo."""
    app = create_app(
        get_state=lambda: _make_state(repos=[{"name": "my-repo", "branch": "main", "ahead": 0, "behind": 0, "pull_status": None, "has_forge": False, "pipeline_status": None, "mr_count": 0, "vuln_critical": 0, "vuln_high": 0, "remote_url": ""}]),
        trigger_refresh=None,
        dismiss_event=None,
    )
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        resp = await c.get("/repo/my-repo")
    assert resp.status_code == 200
    assert "my-repo" in resp.text


async def test_repo_page_not_found(client):
    resp = await client.get("/repo/nonexistent")
    assert resp.status_code == 200
    assert "not found" in resp.text


async def test_pin_returns_204(client):
    resp = await client.post("/action/pin/some-repo", headers={"HX-Request": "true"})
    assert resp.status_code == 204


async def test_exclude_returns_204(client):
    resp = await client.post("/action/exclude/some-repo", headers={"HX-Request": "true"})
    assert resp.status_code == 204


async def test_rescan_returns_204(client):
    resp = await client.post("/action/rescan", headers={"HX-Request": "true"})
    assert resp.status_code == 204


async def test_sync_status_in_progress():
    app = create_app(
        get_state=lambda: _make_state(sync_status="in_progress"),
        trigger_refresh=None,
        dismiss_event=None,
    )
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        resp = await c.get("/fragment/sync-status")
    assert resp.status_code == 200
    assert "aria-busy" in resp.text


async def test_mrs_filter_mine():
    state = _make_state(
        mrs=[
            {"repo_name": "r", "iid": 1, "title": "my mr", "author": "me", "state": "opened", "source_branch": "a", "target_branch": "b", "web_url": "", "user_notes_count": 0, "approved": False},
            {"repo_name": "r", "iid": 2, "title": "other mr", "author": "them", "state": "opened", "source_branch": "c", "target_branch": "d", "web_url": "", "user_notes_count": 0, "approved": False},
        ],
        usernames={"gitlab.com": "me"},
    )
    app = create_app(get_state=lambda: state, trigger_refresh=None, dismiss_event=None)
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        resp = await c.get("/fragment/mrs?filter=mine")
    assert "my mr" in resp.text
    assert "other mr" not in resp.text
