from __future__ import annotations

import asyncio
import logging
import secrets
from typing import List

from appwrite.exception import AppwriteException
from appwrite.query import Query
from fastapi import Depends, FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.openapi.utils import get_openapi

from src.app.api.v1.routes import router as api_v1_router  # contém /ping
from src.core.appwrite_client import get_appwrite_clients
from src.core.auth import get_password_hash
from src.core.config import get_settings
from src.core.deps import require_user
from src.core.security import APIKeyMiddleware
from src.docs.swagger_tags import MERCADO_PAGO_TAG
from src.modules.auth.router import router as auth_router
from src.modules.carrinhos.router import router as carrinhos_router
from src.modules.categorias.router import router as categorias_router
from src.modules.empresas.router import router as empresas_router
from src.modules.empresas_dados.router import router as empresas_dados_router
from src.modules.empresas_socios.router import router as empresas_socios_router
from src.modules.enderecos.router import router as enderecos_router
from src.modules.entregas.router import router as entregas_router
from src.modules.faturas.router import router as faturas_router
from src.modules.laboratorios.router import router as laboratorios_router
from src.modules.pagamentos.router import router as pagamentos_router
from src.modules.pagamentos.router_public import (
    router as mercadopago_public_router,
)
from src.modules.pedidos.router import router as pedidos_router
from src.modules.produtos_catalogo.router import (
    router as produtos_catalogo_router,
)
from src.modules.produtos_estoque.router import (
    router as produtos_estoque_router,
)
from src.modules.produtos_venda.router import router as produtos_venda_router
from src.modules.subcategorias.router import router as subcategorias_router
from src.modules.usuario_empresa_perfis.router import (
    router as usuario_empresa_perfis_router,
)
from src.modules.usuarios.router import router as usuarios_router
from src.modules.usuarios_data.router import router as usuarios_data_router
from src.modules.usuarios_perfil.router import router as usuarios_perfil_router
from src.routers.public.cnpj_router import router as public_cnpj_router

app = FastAPI(
    title="Save in Med",
    version="1.0.0",
    description=(
        "BFF com integracao Appwrite (Databases) para o projeto Save in Med."
    ),
    openapi_url="/openapi.json",
    docs_url="/docs",
    swagger_ui_parameters={"persistAuthorization": True},
    openapi_tags=[
        {"name": "Core", "description": "Rotas basicas do BFF."},
        {"name": "Auth", "description": "Fluxo de autenticacao e sessao."},
        MERCADO_PAGO_TAG,
    ],
)

settings = get_settings()
app.add_middleware(APIKeyMiddleware, api_key=settings.security_api_key)

allow_origins: List[str]
if settings.cors_allow_origins:
    parsed = [
        origin.strip()
        for origin in settings.cors_allow_origins.split(",")
        if origin.strip()
    ]
    allow_origins = parsed or ["*"]
else:
    allow_origins = ["*"]

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

# Routers sem proteção adicional
app.include_router(auth_router)
app.include_router(api_v1_router, prefix="/api/v1")
app.include_router(public_cnpj_router)
app.include_router(mercadopago_public_router)  # /mercadopago/...
app.include_router(
    mercadopago_public_router, prefix="/api/v1"
)  # /api/v1/mercadopago/...

protected_dependencies = [Depends(require_user)]

# Routers dos módulos protegidos (cada um já possui prefixo /api/v1/…)
app.include_router(categorias_router, dependencies=protected_dependencies)
app.include_router(subcategorias_router, dependencies=protected_dependencies)
app.include_router(usuarios_router, dependencies=protected_dependencies)
app.include_router(empresas_router, dependencies=protected_dependencies)
app.include_router(empresas_dados_router, dependencies=protected_dependencies)
app.include_router(empresas_socios_router, dependencies=protected_dependencies)
app.include_router(enderecos_router, dependencies=protected_dependencies)

if (
    settings.appwrite_collection_entregas_id
    and settings.appwrite_collection_entregas_id.strip()
):
    app.include_router(entregas_router, dependencies=protected_dependencies)
else:
    logging.warning(
        "Entregas router disabled: APPWRITE_COLLECTION_ENTREGAS_ID is not "
        "configured."
    )

app.include_router(
    produtos_catalogo_router,
    dependencies=protected_dependencies,
)
app.include_router(faturas_router, dependencies=protected_dependencies)
app.include_router(laboratorios_router, dependencies=protected_dependencies)
app.include_router(carrinhos_router, dependencies=protected_dependencies)
app.include_router(pedidos_router, dependencies=protected_dependencies)
app.include_router(pagamentos_router, dependencies=protected_dependencies)
app.include_router(
    produtos_estoque_router,
    dependencies=protected_dependencies,
)
app.include_router(produtos_venda_router, dependencies=protected_dependencies)
app.include_router(usuarios_perfil_router, dependencies=protected_dependencies)
app.include_router(
    usuario_empresa_perfis_router,
    dependencies=protected_dependencies,
)
app.include_router(usuarios_data_router, dependencies=protected_dependencies)


def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema

    settings = get_settings()
    schema = get_openapi(
        title="Save in Med BFF",
        version="0.1.0",
        description="BFF do Save in Med",
        routes=app.routes,
    )
    if app.openapi_tags:
        schema["tags"] = app.openapi_tags
    components = schema.setdefault("components", {})
    security_schemes = components.setdefault("securitySchemes", {})
    security_schemes["BearerAuth"] = {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
    }
    security_schemes["CookieAuth"] = {
        "type": "apiKey",
        "in": "cookie",
        "name": settings.session_cookie_name,
    }
    security_requirements = [{"BearerAuth": []}, {"CookieAuth": []}]

    if settings.security_api_key:
        security_schemes["ApiKeyAuth"] = {
            "type": "apiKey",
            "in": "header",
            "name": "x-api-key",
        }
        # Quando a chave esta configurada, exigimos x-api-key
        # + (Bearer ou Cookie)
        security_requirements = [
            {"ApiKeyAuth": [], "BearerAuth": []},
            {"ApiKeyAuth": [], "CookieAuth": []},
        ]

    schema["security"] = security_requirements
    app.openapi_schema = schema
    return app.openapi_schema


app.openapi = custom_openapi


@app.get("/", tags=["Core"])
async def read_root() -> dict[str, str]:
    return {"name": "Save in Med BFF"}


@app.get("/healthz", tags=["Core"])
async def health_check() -> dict[str, str]:
    return {"status": "ok"}


@app.on_event("startup")
async def seed_superadmin() -> None:
    settings = get_settings()
    identificador = settings.superadmin_identificador.strip()
    senha = (settings.superadmin_senha or "").strip()

    if not identificador:
        return

    if not senha or len(senha) > 1024:
        logging.warning(
            "SUPERADMIN_SENHA invalida (vazia ou muito longa); gerando "
            "temporaria segura."
        )
        senha = secrets.token_urlsafe(24)

    _, databases = get_appwrite_clients()

    try:
        existing = await asyncio.to_thread(
            databases.list_documents,
            settings.appwrite_database_id,
            settings.appwrite_collection_usuarios_id,
            [Query.equal("superadmin", True)],
        )
    except AppwriteException:
        return

    if existing.get("total", 0):
        return

    hashed_password = get_password_hash(senha)
    data = {
        "identificador": identificador,
        "senha": hashed_password,
        "ativo": True,
        "superadmin": True,
    }

    try:
        await asyncio.to_thread(
            databases.create_document,
            settings.appwrite_database_id,
            settings.appwrite_collection_usuarios_id,
            document_id="unique()",
            data=data,
        )
    except AppwriteException:
        return
