# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Admin log viewer routes for the backend API.
Sysadmin-only endpoint for viewing gateway application logs.
Reads from the daily rotating log files (log_app_YYYYMMDD.log).
"""

import os
import glob
import logging
from datetime import datetime
from fastapi import APIRouter, HTTPException, Depends, Request, Query
from fastapi.responses import PlainTextResponse
from modules.auth import limiter, requireSysAdminRole
from modules.shared.configuration import APP_CONFIG
from modules.datamodels.datamodelUam import User

logger = logging.getLogger(__name__)

router = APIRouter(
    prefix="/api/admin/logs",
    tags=["Admin Logs"],
    responses={
        401: {"description": "Unauthorized"},
        403: {"description": "Forbidden - Sysadmin only"},
        500: {"description": "Internal server error"},
    },
)


def _getLogDir() -> str:
    """Resolve the configured log directory (same logic as app.py initLogging)."""
    logDir = APP_CONFIG.get("APP_LOGGING_LOG_DIR", "./")
    if not os.path.isabs(logDir):
        gatewayDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
        logDir = os.path.join(gatewayDir, logDir)
    return logDir


def _getLogFiles() -> list[str]:
    """Return all log_app_*.log files sorted by name descending (newest first)."""
    logDir = _getLogDir()
    pattern = os.path.join(logDir, "log_app_*.log")
    files = glob.glob(pattern)
    files.sort(reverse=True)
    return files


def _readLastNLines(filePath: str, n: int) -> list[str]:
    """Read last n lines from a file efficiently."""
    lines = []
    try:
        with open(filePath, "r", encoding="utf-8", errors="replace") as f:
            lines = f.readlines()
    except Exception as e:
        logger.warning(f"Failed to read log file {filePath}: {e}")
    return lines[-n:] if len(lines) > n else lines


@router.get("")
@limiter.limit("30/minute")
def getLogEntries(
    request: Request,
    count: int = Query(default=200, ge=1, le=50000, description="Number of log entries to return"),
    currentUser: User = Depends(requireSysAdminRole),
) -> dict:
    """
    Get the last N log entries from the gateway log files.
    Merges across multiple daily log files if needed.
    """
    try:
        logFiles = _getLogFiles()

        if not logFiles:
            return {"lines": [], "totalCollected": 0, "logDir": _getLogDir()}

        collectedLines: list[str] = []
        remaining = count

        for filePath in logFiles:
            if remaining <= 0:
                break

            lines = _readLastNLines(filePath, remaining)
            collectedLines = lines + collectedLines
            remaining = count - len(collectedLines)

        finalLines = collectedLines[-count:] if len(collectedLines) > count else collectedLines

        return {
            "lines": [line.rstrip("\n").rstrip("\r") for line in finalLines],
            "totalCollected": len(finalLines),
            "logDir": _getLogDir(),
        }

    except Exception as e:
        logger.error(f"Failed to read log files: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to read log files: {str(e)}")


@router.get("/download")
@limiter.limit("10/minute")
def downloadLog(
    request: Request,
    count: int = Query(default=1000, ge=1, le=100000, description="Number of log entries to download"),
    currentUser: User = Depends(requireSysAdminRole),
) -> PlainTextResponse:
    """
    Download the last N log entries as a plain text file.
    """
    try:
        logFiles = _getLogFiles()

        if not logFiles:
            return PlainTextResponse("No log files found.", media_type="text/plain")

        collectedLines: list[str] = []
        remaining = count

        for filePath in logFiles:
            if remaining <= 0:
                break

            lines = _readLastNLines(filePath, remaining)
            collectedLines = lines + collectedLines
            remaining = count - len(collectedLines)

        finalLines = collectedLines[-count:] if len(collectedLines) > count else collectedLines
        content = "".join(finalLines)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

        return PlainTextResponse(
            content=content,
            media_type="text/plain",
            headers={
                "Content-Disposition": f'attachment; filename="gateway_log_{timestamp}.log"',
            },
        )

    except Exception as e:
        logger.error(f"Failed to download log files: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to download log files: {str(e)}")
