import logging
import os
import secrets
from logging.handlers import RotatingFileHandler
from fastapi.responses import JSONResponse
import sys
sys.path.insert(0, "/var/www/html/metafoliadorv2")

from fastapi import FastAPI, Request, Depends, HTTPException, status
from fastapi.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html
from fastapi.openapi.utils import get_openapi
from fastapi.security import HTTPBasic, HTTPBasicCredentials

from app.config import settings
from app.api.routes.auth import router as auth_router
from app.api.routes.views import router as views_router
from app.api.routes.stats import router as stats_router
from app.api.routes.connections import router as connections_router
from app.api.routes.sites import router as sites_router
from app.api.routes.folders import router as folders_router
from app.api.routes.jobs import router as jobs_router
from app.api.routes.users_admin import router as users_admin_router
from app.api.routes.alfresco_listener import router as alfresco_listener_router
from app.api.routes.admin_rbac import router as admin_rbac_router
from app.api.routes.listener_logs_view import router as listener_logs_view_router
from app.api.routes.reportes import router as reportes_router
from app.api.routes.reportes_gen import router as reportes_gen_router
from app.api.routes.tipologias import router as tipologias_router

from app.api.main.auth import router as main_auth_router
from app.api.main.customers import router as main_customers_router
from app.api.main.users import router as main_users_router
from app.api.main.views import router as main_views_router

from app.middleware import TenantMiddleware

log_dir = "/var/www/html/metafoliadorv2/logs"
os.makedirs(log_dir, exist_ok=True)
error_handler = RotatingFileHandler(f"{log_dir}/api.log", maxBytes=10485760, backupCount=30)
error_handler.setLevel(logging.ERROR)
error_handler.setFormatter(logging.Formatter("[%(asctime)s] %(levelname)s: %(name)s:%(lineno)d - %(message)s"))
logging.getLogger().addHandler(error_handler)

logging.basicConfig(
    level=getattr(logging, settings.log_level.upper(), logging.INFO),
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)

tags_metadata = [
    {"name": "auth", "description": "Autenticación y gestión de sesiones JWT. Login, logout e información del usuario autenticado."},
    {"name": "views", "description": "Vistas HTML del panel administrativo. Páginas renderizadas con Jinja2 para la interfaz web."},
    {"name": "stats", "description": "Estadísticas del dashboard. Conteo de sitios, Series, Subseries y Expedientes, archivos, índices y datos para gráficos."},
    {"name": "connections", "description": "CRUD de conexiones a instancias Alfresco. Gestión de URLs, credenciales, test y descubrimiento de sitios."},
    {"name": "sites", "description": "CRUD de sitios Alfresco. Sincronización, activación y gestión de sitios documentales."},
    {"name": "folders", "description": "Cuadro de clasificación, sincronización recursiva y generación de índices electrónicos (index.xml)."},
    {"name": "jobs", "description": "Monitoreo y control de trabajos en cola Celery. Cancelación y purga de tareas."},
    {"name": "users", "description": "CRUD de usuarios del sistema. Creación, edición, activación/desactivación de cuentas."},
    {"name": "alfresco-listener", "description": "Webhook listener para recibir eventos de Alfresco (create/update/delete/move de archivos, Series, Subseries y Expedientes)."},
    {"name": "admin", "description": "Administración RBAC. Roles y 32 permisos granulares del sistema."},
    {"name": "listener-logs", "description": "Visor de logs del webhook listener. Historial de peticiones recibidas de Alfresco."},
    {"name": "reportes", "description": "Gestión de reportes. Listado, activación/inactivación y generación de reportes disponibles."},
    {"name": "reportes-gen", "description": "Generación de reportes Excel (TRD/Tipologías) y PDF (Gráficos por Dependencia)."},
    {"name": "tipologias", "description": "Sincronización y gestión de modelos de datos personalizados de Alfresco. Filtrado de modelos del sistema y marcado de tipologías."},
]

app = FastAPI(
    title="Metafoliador v2 API",
    description="API para gestión de índices electrónicos documentales con integración Alfresco ECM. "
                "Formato colombiano TipoDocumentoFoliado, sincronización de Series, Subseries y Expedientes/archivos, "
                "cálculo de hash SHA-256, conteo de páginas, webhook listener, panel RBAC y reportes.",
    version="2.0.0",
    docs_url=None,
    redoc_url=None,
    openapi_url=None,
    openapi_tags=tags_metadata,
    contact={
        "name": "MetaBiblioteca",
    },
    license_info={
        "name": "Propietario",
    },
)

app.add_middleware(TenantMiddleware)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.mount("/static", StaticFiles(directory="/var/www/html/metafoliadorv2/static"), name="static")

app.include_router(main_auth_router)
app.include_router(main_customers_router)
app.include_router(main_users_router)
app.include_router(main_views_router)

app.include_router(folders_router)
app.include_router(auth_router)
app.include_router(stats_router)
app.include_router(connections_router)
app.include_router(sites_router)
app.include_router(jobs_router)
app.include_router(users_admin_router)
app.include_router(alfresco_listener_router)
app.include_router(admin_rbac_router)
app.include_router(listener_logs_view_router)
app.include_router(reportes_gen_router)
app.include_router(reportes_router)
app.include_router(tipologias_router)
app.include_router(views_router)

security = HTTPBasic()


def verify_swagger_credentials(credentials: HTTPBasicCredentials = Depends(security)):
    correct_username = secrets.compare_digest(credentials.username.encode(), settings.swagger_username.encode())
    correct_password = secrets.compare_digest(credentials.password.encode(), settings.swagger_password.encode())
    if not (correct_username and correct_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Credenciales inválidas para la documentación de la API",
            headers={"WWW-Authenticate": "Basic"},
        )
    return credentials


@app.get("/docs", include_in_schema=False)
async def swagger_ui(credentials: HTTPBasicCredentials = Depends(verify_swagger_credentials)):
    return get_swagger_ui_html(
        openapi_url="/openapi.json",
        title="Metafoliador v2 API - Swagger UI",
    )


@app.get("/redoc", include_in_schema=False)
async def redoc_ui(credentials: HTTPBasicCredentials = Depends(verify_swagger_credentials)):
    return get_redoc_html(
        openapi_url="/openapi.json",
        title="Metafoliador v2 API - ReDoc",
    )


@app.get("/openapi.json", include_in_schema=False)
async def openapi_schema(credentials: HTTPBasicCredentials = Depends(verify_swagger_credentials)):
    return get_openapi(
        title=app.title,
        version=app.version,
        description=app.description,
        tags=app.openapi_tags,
        routes=app.routes,
    )


@app.get("/")
async def root(request: Request):
    if request.state.is_main:
        return RedirectResponse(url="/main")
    return RedirectResponse(url="/login")


@app.exception_handler(401)
async def auth_401_handler(request, exc):
    accept = request.headers.get("accept", "")
    path = request.url.path
    if path.startswith("/api/"):
        return JSONResponse(
            status_code=401,
            content={"detail": str(exc.detail)},
            headers=getattr(exc, "headers", {}),
        )
    if path in ("/docs", "/redoc", "/openapi.json"):
        return JSONResponse(
            status_code=401,
            content={"detail": str(exc.detail)},
            headers=getattr(exc, "headers", {}),
        )
    if "text/html" in accept:
        is_main = getattr(request.state, "is_main", False)
        redirect_url = "/main/login" if is_main else "/login"
        return RedirectResponse(url=redirect_url, status_code=302)
    return JSONResponse(status_code=401, content={"detail": str(exc.detail)})


@app.exception_handler(403)
async def auth_403_handler(request, exc):
    accept = request.headers.get("accept", "")
    path = request.url.path
    if path.startswith("/api/"):
        return JSONResponse(
            status_code=403,
            content={"detail": str(exc.detail)},
            headers=getattr(exc, "headers", {}),
        )
    if "text/html" in accept:
        is_main = getattr(request.state, "is_main", False)
        redirect_url = "/main/login" if is_main else "/login"
        return RedirectResponse(url=redirect_url, status_code=302)
    return JSONResponse(status_code=403, content={"detail": str(exc.detail)})
