"""Nexus — Global Search API Route
Cross-entity search across servers, scripts, credentials, and schedules.
All operations require JWT authentication.
"""

import logging

from fastapi import APIRouter, Depends, Query

from server.api.dependencies import get_db
from server.api.auth_jwt import get_current_admin
from server.domain.models import Admin, Server, Script, DbCredential, PushSchedule

from sqlalchemy import or_
from sqlalchemy.ext.asyncio import AsyncSession

router = APIRouter(prefix="/api/search", tags=["search"])

logger = logging.getLogger("nexus.search")


def _escape_like(s: str) -> str:
    """Escape LIKE wildcard characters in user input.

    Without this, a user searching for ``%`` matches all rows and ``_``
    matches any single character — a form of information disclosure.
    """
    return s.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")


@router.get("/", response_model=dict)
async def global_search(
    q: str = Query(..., min_length=1, max_length=100, description="Search query"),
    admin: Admin = Depends(get_current_admin),
    db: AsyncSession = Depends(get_db),
):
    """Global search across servers, scripts, credentials, and schedules.

    Returns top 10 matches per entity type.
    """
    from sqlalchemy import select

    pattern = f"%{_escape_like(q)}%"
    results = {"servers": [], "scripts": [], "credentials": [], "schedules": []}

    # Servers
    try:
        stmt = select(Server).where(
            or_(
                Server.name.ilike(pattern, escape="\\"),
                Server.domain.ilike(pattern, escape="\\"),
                Server.description.ilike(pattern, escape="\\"),
                Server.category.ilike(pattern, escape="\\"),
            )
        ).limit(10)
        res = await db.execute(stmt)
        for s in res.scalars().all():
            results["servers"].append({
                "id": s.id, "name": s.name, "domain": s.domain,
                "category": s.category, "is_online": s.is_online,
            })
    except Exception:
        logger.warning("Search failed for 'servers' entity", exc_info=True)

    # Scripts
    try:
        stmt = select(Script).where(
            or_(
                Script.name.ilike(pattern, escape="\\"),
                Script.category.ilike(pattern, escape="\\"),
                Script.description.ilike(pattern, escape="\\"),
            )
        ).limit(10)
        res = await db.execute(stmt)
        for s in res.scalars().all():
            results["scripts"].append({
                "id": s.id, "name": s.name, "category": s.category,
            })
    except Exception:
        logger.warning("Search failed for 'scripts' entity", exc_info=True)

    # Credentials
    try:
        stmt = select(DbCredential).where(
            or_(
                DbCredential.name.ilike(pattern, escape="\\"),
                DbCredential.host.ilike(pattern, escape="\\"),
            )
        ).limit(10)
        res = await db.execute(stmt)
        for c in res.scalars().all():
            results["credentials"].append({
                "id": c.id, "name": c.name, "db_type": c.db_type, "host": c.host,
            })
    except Exception:
        logger.warning("Search failed for 'credentials' entity", exc_info=True)

    # Schedules
    try:
        stmt = select(PushSchedule).where(
            or_(
                PushSchedule.name.ilike(pattern, escape="\\"),
                PushSchedule.source_path.ilike(pattern, escape="\\"),
            )
        ).limit(10)
        res = await db.execute(stmt)
        for s in res.scalars().all():
            results["schedules"].append({
                "id": s.id, "name": s.name, "cron_expr": s.cron_expr, "enabled": s.enabled,
            })
    except Exception:
        logger.warning("Search failed for 'schedules' entity", exc_info=True)

    # Total count
    total = sum(len(v) for v in results.values())
    results["total"] = total
    results["query"] = q

    return results
