"""Internal (operator-only) routes.

Two defense layers protect this path:

1. **nginx** blocks ``/internal/*`` at the public server-block level
   (``location /internal/ { return 404; }`` in
   ``docs/SETUP-LICENSE-SERVER.md``).
2. **Bearer token** authenticates the operator's CLI.

An earlier draft also enforced a peer-IP loopback check here, but
that fights the Docker bridge network model: the container always
sees the gateway IP (172.x.0.1) regardless of whether traffic
originated from nginx on the host or from outside. The check is
preserved as :func:`app.auth.require_localhost` for future use
(e.g. if the API ever runs in ``network_mode: host``).
"""

from __future__ import annotations

from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import func, select
from sqlalchemy.orm import Session

from app.adapters.manual import ManualAdapter
from app.auth import require_bearer_token
from app.db import get_session
from app.mint import mint_from_sale, revoke_license
from app.models import License
from app.schemas import LicenseResponse, MintRequest, RevokeRequest

router = APIRouter(
    prefix="/internal",
    dependencies=[Depends(require_bearer_token)],
)

_MANUAL = ManualAdapter()


@router.post("/mint", response_model=LicenseResponse, status_code=status.HTTP_201_CREATED)
def mint(req: MintRequest, session: Session = Depends(get_session)) -> License:
    """Mint a license blob and persist the row.

    PR 1 only wires the ``manual`` source through this endpoint. Real
    storefront sales (Gumroad et al.) arrive via per-source webhook
    handlers in PR 2 and bypass this route entirely.
    """
    if req.source != "manual":
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=(
                f"Source {req.source!r} is not wired for direct mints. "
                "Storefront sales arrive via /webhooks/* (PR 2)."
            ),
        )
    sale = _MANUAL.build_sale(
        name=req.name,
        email=req.email,
        tier=req.tier.value,
        years=req.years,
        promotion=req.promotion,
        amount_paid=req.amount_paid,
        currency=req.currency,
        notes=req.notes,
    )
    return mint_from_sale(session, sale)


@router.post("/revoke", response_model=LicenseResponse)
def revoke(req: RevokeRequest, session: Session = Depends(get_session)) -> License:
    row = revoke_license(session, license_key=req.license_key, reason=req.reason)
    if row is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="License not found")
    return row


@router.get("/licenses", response_model=list[LicenseResponse])
def list_licenses(
    email: Optional[str] = Query(default=None, description="Case-insensitive email substring."),
    tier: Optional[str] = Query(default=None),
    source: Optional[str] = Query(default=None),
    include_revoked: bool = Query(default=False),
    limit: int = Query(default=50, ge=1, le=500),
    offset: int = Query(default=0, ge=0),
    session: Session = Depends(get_session),
) -> list[License]:
    stmt = select(License).order_by(License.created_at.desc()).limit(limit).offset(offset)
    if email:
        stmt = stmt.where(func.lower(License.email).contains(email.lower()))
    if tier:
        stmt = stmt.where(License.tier == tier)
    if source:
        stmt = stmt.where(License.source == source)
    if not include_revoked:
        stmt = stmt.where(License.revoked_at.is_(None))
    return list(session.execute(stmt).scalars().all())


@router.get("/ping")
def ping() -> dict:
    """Sanity-check both guards from inside an SSH tunnel."""
    return {"ok": True}
