# ruff: noqa: INP001
"""Integration tests for Forgejo connection CRUD behavior."""

from __future__ import annotations

from datetime import datetime
from uuid import uuid4

import pytest
from fastapi import APIRouter, FastAPI
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import AsyncEngine, async_sessionmaker, create_async_engine
from sqlmodel import SQLModel, col, select
from sqlmodel.ext.asyncio.session import AsyncSession

from app import models as _models
from app.api.deps import require_org_member
from app.api.forgejo_connections import router as forgejo_connections_router
from app.db.session import get_session
from app.models.board_repository_links import BoardRepositoryLink
from app.models.boards import Board
from app.models.forgejo_connections import ForgejoConnection
from app.models.forgejo_issues import ForgejoIssue
from app.models.forgejo_repositories import ForgejoRepository
from app.models.organization_members import OrganizationMember
from app.models.organizations import Organization
from app.services.organizations import OrganizationContext


async def _make_engine() -> AsyncEngine:
    engine = create_async_engine("sqlite+aiosqlite:///:memory:")
    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)
    return engine


def _build_test_app(
    session_maker: async_sessionmaker[AsyncSession],
    ctx: OrganizationContext,
) -> FastAPI:
    app = FastAPI()
    api_v1 = APIRouter(prefix="/api/v1")
    api_v1.include_router(forgejo_connections_router)
    app.include_router(api_v1)

    async def _override_get_session() -> AsyncSession:
        async with session_maker() as session:
            yield session

    async def _override_require_org_member() -> OrganizationContext:
        return ctx

    app.dependency_overrides[get_session] = _override_get_session
    app.dependency_overrides[require_org_member] = _override_require_org_member
    return app


@pytest.mark.asyncio
async def test_delete_connection_removes_repositories_and_dependents() -> None:
    engine = await _make_engine()
    session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
    organization = Organization(id=uuid4(), name="Pipeline")
    member = OrganizationMember(
        id=uuid4(),
        organization_id=organization.id,
        user_id=uuid4(),
        role="owner",
    )
    app = _build_test_app(
        session_maker,
        OrganizationContext(organization=organization, member=member),
    )

    connection = ForgejoConnection(
        id=uuid4(),
        organization_id=organization.id,
        name="Dream Forgejo",
        base_url="https://forgejo.example.local",
    )
    repository = ForgejoRepository(
        id=uuid4(),
        organization_id=organization.id,
        connection_id=connection.id,
        owner="openclaw",
        repo="pipeline",
        display_name="Pipeline",
    )
    board = Board(
        id=uuid4(),
        organization_id=organization.id,
        name="Pipeline Board",
        slug="pipeline-board",
    )
    issue = ForgejoIssue(
        id=uuid4(),
        organization_id=organization.id,
        repository_id=repository.id,
        forgejo_issue_number=42,
        title="Sync issue",
        body_preview="Cached issue body",
        state="open",
        is_pull_request=False,
        labels=[],
        assignees=[],
        author="kaspa",
        html_url="https://forgejo.example.local/openclaw/pipeline/issues/42",
        forgejo_created_at=datetime(2026, 5, 19, 12, 0, 0),
        forgejo_updated_at=datetime(2026, 5, 19, 12, 5, 0),
    )
    link = BoardRepositoryLink(
        id=uuid4(),
        organization_id=organization.id,
        board_id=board.id,
        repository_id=repository.id,
    )

    try:
        async with session_maker() as session:
            session.add(organization)
            session.add(connection)
            session.add(repository)
            session.add(board)
            session.add(issue)
            session.add(link)
            await session.commit()

        async with AsyncClient(
            transport=ASGITransport(app=app),
            base_url="http://testserver",
        ) as client:
            response = await client.delete(f"/api/v1/forgejo/connections/{connection.id}")

        assert response.status_code == 200
        assert response.json() == {"ok": True}

        async with session_maker() as session:
            assert (
                await session.exec(
                    select(ForgejoConnection).where(col(ForgejoConnection.id) == connection.id)
                )
            ).first() is None
            assert (
                await session.exec(
                    select(ForgejoRepository).where(col(ForgejoRepository.id) == repository.id)
                )
            ).first() is None
            assert (
                await session.exec(select(ForgejoIssue).where(col(ForgejoIssue.id) == issue.id))
            ).first() is None
            assert (
                await session.exec(
                    select(BoardRepositoryLink).where(col(BoardRepositoryLink.id) == link.id)
                )
            ).first() is None
            assert (
                await session.exec(select(Board).where(col(Board.id) == board.id))
            ).first() is not None
    finally:
        await engine.dispose()


@pytest.mark.asyncio
async def test_update_connection_blank_token_keeps_existing_token() -> None:
    engine = await _make_engine()
    session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
    organization = Organization(id=uuid4(), name="Pipeline")
    member = OrganizationMember(
        id=uuid4(),
        organization_id=organization.id,
        user_id=uuid4(),
        role="owner",
    )
    app = _build_test_app(
        session_maker,
        OrganizationContext(organization=organization, member=member),
    )

    connection = ForgejoConnection(
        id=uuid4(),
        organization_id=organization.id,
        name="Dream Forgejo",
        base_url="https://forgejo.example.local",
        token="temp-token-12345678",
        token_last_eight="12345678",
    )

    try:
        async with session_maker() as session:
            session.add(organization)
            session.add(connection)
            await session.commit()

        async with AsyncClient(
            transport=ASGITransport(app=app),
            base_url="http://testserver",
        ) as client:
            response = await client.patch(
                f"/api/v1/forgejo/connections/{connection.id}",
                json={"name": "Dream Forgejo Updated", "token": ""},
            )

        assert response.status_code == 200
        data = response.json()
        assert data["name"] == "Dream Forgejo Updated"
        assert data["has_token"] is True
        assert data["token_last_eight"] == "12345678"

        async with session_maker() as session:
            saved = (
                await session.exec(
                    select(ForgejoConnection).where(col(ForgejoConnection.id) == connection.id)
                )
            ).one()
            assert saved.token == "temp-token-12345678"
            assert saved.token_last_eight == "12345678"
    finally:
        await engine.dispose()
