"""CRUD for `crawl_target` (§5.3)."""
from __future__ import annotations

from typing import Any

from sqlalchemy import select
from sqlalchemy.orm import Session

from govcrawler.models import CrawlTarget


def get_by_code(session: Session, target_code: str) -> CrawlTarget | None:
    return session.scalar(
        select(CrawlTarget).where(CrawlTarget.target_code == target_code)
    )


def get_by_id(session: Session, target_id: int) -> CrawlTarget | None:
    return session.get(CrawlTarget, target_id)


def list_for_site(
    session: Session, site_id: int, *, enabled_only: bool = True
) -> list[CrawlTarget]:
    stmt = select(CrawlTarget).where(CrawlTarget.site_id == site_id)
    if enabled_only:
        stmt = stmt.where(CrawlTarget.enabled.is_(True))
    # Newest-first so the admin UI surfaces just-created targets at the top.
    # Tiebreaker on id keeps order stable when created_at ties (server_default
    # = NOW(), but bulk-create can collide within the same second).
    return list(
        session.scalars(
            stmt.order_by(CrawlTarget.created_at.desc(), CrawlTarget.id.desc())
        )
    )


def list_for_dept(session: Session, site_department_id: int) -> list[CrawlTarget]:
    return list(
        session.scalars(
            select(CrawlTarget)
            .where(CrawlTarget.site_department_id == site_department_id)
            .order_by(CrawlTarget.id)
        )
    )


def upsert_by_code(
    session: Session,
    *,
    target_code: str,
    site_id: int,
    site_department_id: int | None = None,
    **fields: Any,
) -> CrawlTarget:
    """Create-or-update on target_code (globally unique per §5.3)."""
    row = get_by_code(session, target_code)
    if row is None:
        row = CrawlTarget(
            target_code=target_code,
            site_id=site_id,
            site_department_id=site_department_id,
            **fields,
        )
        session.add(row)
    else:
        row.site_id = site_id
        row.site_department_id = site_department_id
        for k, v in fields.items():
            setattr(row, k, v)
    return row


def set_enabled(
    session: Session, target_code: str, enabled: bool
) -> CrawlTarget | None:
    row = get_by_code(session, target_code)
    if row is not None:
        row.enabled = enabled
    return row
