from fastapi import HTTPException
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from api.database import get_session
from api.models.domain import Domain
from api.models.extension_point import ExtensionPoint
from api.models.managed_repo import ManagedRepo
from api.models.technical_debt import TechnicalDebt
from api.models.topic import Topic
from api.models.workplan import Workplan
from api.schemas.domain import (
    DomainCreate,
    DomainDetail,
    DomainRead,
    DomainRename,
    DomainUpdate,
    RepoStub,
)
from hub_core.routers.domains import create_domains_router


async def _build_domain_detail(domain: Domain, session: AsyncSession) -> DomainDetail:
    topic_count_row = await session.execute(
        select(func.count()).select_from(Topic).where(Topic.domain_id == domain.id)
    )
    topic_count = topic_count_row.scalar_one()

    topic_ids_row = await session.execute(select(Topic.id).where(Topic.domain_id == domain.id))
    topic_ids = [row[0] for row in topic_ids_row.all()]

    workstream_count = 0
    if topic_ids:
        workstream_count_row = await session.execute(
            select(func.count()).select_from(Workplan)
            .where(Workplan.topic_id.in_(topic_ids))
            .where(Workplan.status == "active")
        )
        workstream_count = workstream_count_row.scalar_one()

    ep_count_row = await session.execute(
        select(func.count()).select_from(ExtensionPoint)
        .where(ExtensionPoint.domain_id == domain.id)
    )
    td_count_row = await session.execute(
        select(func.count()).select_from(TechnicalDebt)
        .where(TechnicalDebt.domain_id == domain.id)
    )
    repos_row = await session.execute(
        select(ManagedRepo)
        .where(ManagedRepo.domain_id == domain.id)
        .where(ManagedRepo.status == "active")
        .order_by(ManagedRepo.name)
    )
    repos = list(repos_row.scalars().all())

    return DomainDetail(
        id=domain.id,
        slug=domain.slug,
        name=domain.name,
        description=domain.description,
        status=domain.status,
        created_at=domain.created_at,
        updated_at=domain.updated_at,
        topic_count=topic_count,
        workstream_count=workstream_count,
        ep_count=ep_count_row.scalar_one(),
        td_count=td_count_row.scalar_one(),
        repos=[RepoStub.model_validate(repo) for repo in repos],
    )


async def _reject_archive_with_active_topics(domain: Domain, session: AsyncSession) -> None:
    active_topics = await session.execute(
        select(func.count()).select_from(Topic)
        .where(Topic.domain_id == domain.id)
        .where(Topic.status == "active")
    )
    if active_topics.scalar_one() > 0:
        raise HTTPException(
            status_code=409,
            detail="Cannot archive domain with active topics. Archive or reassign topics first.",
        )


router = create_domains_router(
    get_session,
    domain_model=Domain,
    repo_model=ManagedRepo,
    domain_create_schema=DomainCreate,
    domain_detail_schema=DomainDetail,
    domain_read_schema=DomainRead,
    domain_rename_schema=DomainRename,
    domain_update_schema=DomainUpdate,
    repo_stub_schema=RepoStub,
    detail_builder=_build_domain_detail,
    before_archive=_reject_archive_with_active_topics,
    list_noload_fields=("topics", "repos", "goals"),
    include_update_route=False,
)

__all__ = ["router"]
