import logging
import traceback

from pathlib import Path
from dotenv import load_dotenv
from fastapi.responses import JSONResponse
from fastapi import FastAPI, Request, status
from scalar_fastapi import get_scalar_api_reference
from controllers.alerta_cliente import router as alerta_cliente_router
from controllers.omie_cliente import router as omie_cliente_router
from controllers.omie_contas_receber import router as omie_contas_receber_router
from controllers.omie_contratos import router as omie_contratos_router
from controllers.auth import router as auth_router

env_path = Path(__file__).parent / '.env'
load_dotenv(dotenv_path=env_path)

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)

logger.info("Iniciando aplicação FastAPI...")

tags_metadata = [
    {"name": "Health", "description": "Verificações de disponibilidade e status do serviço."},
    {"name": "Autenticação", "description": "Rotas de autenticação - Login e validação de usuários (tabelas dbo.Usuario e dbo.Cliente no SQL Server)."},
    {"name": "Alerta Fiscal - Cadastro Clientes Alerta Fiscal", "description": "Rotas do sistema Alerta Fiscal - Consulta de clientes no SQL Server (tabela dbo.Cliente)."},
    {"name": "Omie - Cadastro Clientes Omie", "description": "Rotas da Omie - Consulta de clientes no MySQL (tabela omie_cliente)."},
    {"name": "Omie - Contas a Receber", "description": "Rotas da Omie - Consulta de contas a receber no MySQL (tabelas omie_contaReceber e omie_contaReceber_boleto)."},
    {"name": "Omie - Contratos", "description": "Rotas da Omie - Consulta de contratos no MySQL (tabelas omie_contrato, omie_contrato_servico, omie_contrato_departamento, omie_contrato_vencimentoTexto)."},
]

app = FastAPI(
    title="Hackaton Alerta API",
    version="1.0.0",
    description=(
        "**API de Integração**\n\n"
        "Fornece endpoints para consulta de dados do sistema Alerta Fiscal e da Omie.\n\n"
        "---\n\n"
        "**⚠️ IMPORTANTE - DIFERENCIAÇÃO DE BANCOS DE DADOS:**\n\n"
        "- **Rotas do Alerta Fiscal**: Consultam o **SQL Server** (cadastro interno do sistema)\n"
        "- **Rotas da Omie**: Consultam o **MySQL (DataLake)** (dados da Omie)\n\n"
        "Cada rota documenta claramente qual banco de dados e tabela está sendo consultada.\n\n"
        "---\n\n"
        "**Módulos Disponíveis:**\n\n"
        "1. **Autenticação**\n"
        "   - Login de usuários e validação de tokens (SQL Server)\n\n"
        "2. **Alerta Fiscal - Cadastro Clientes Alerta Fiscal**\n"
        "   - Consulta clientes do cadastro interno (SQL Server)\n\n"
        "3. **Omie - Cadastro Clientes Omie**\n"
        "   - Consulta clientes cadastrados na Omie (MySQL)\n\n"
        "4. **Omie - Contas a Receber**\n"
        "   - Consulta contas a receber e boletos da Omie (MySQL)\n\n"
        "5. **Omie - Contratos**\n"
        "   - Consulta contratos, serviços, departamentos e vencimentos da Omie (MySQL)\n\n"
        "---\n\n"
        "**Autenticação**\n\n"
        "- **Login**: Use `/auth/login` para obter o token do cliente\n"
        "- **Token Fixo**: Use header `Authorization: Bearer <token>` com o token fixo da API (FIX_API_TOKEN)\n"
        "- **Token de Cliente**: Use header `Authorization: Bearer <token>` com o token do cliente retornado no login\n\n"
        "**Formato das Requisições**\n\n"
        "- JSON para consultas.\n\n"
        "**Tratamento de Erros**\n\n"
        "- Respostas padronizadas contendo: `code`, `message`, `details` e `path` (quando aplicável).\n\n"
        "**Boas Práticas de Uso**\n\n"
        "- Prefira filtros opcionais nas consultas para reduzir volume de dados.\n"
        "- Verifique a documentação de cada rota para entender qual banco de dados está sendo consultado.\n\n"
        "---\n\n"
        "Para suporte, utilize os contatos informados em `contact` abaixo.\n\n"
        "**Metadados**\n\n"
        "- Termos de Serviço: https://auditto.com.br\n"
        "- Contato: Equipe — felipe.martinez@grupopomin.com.br\n"
        "- Licença: Auditto — https://auditto.com.br"
    ),
    terms_of_service="https://auditto.com.br",
    contact={
        "name": "Equipe POMIND",
        "url": "https://auditto.com.br",
        "email": "felipe.martinez@grupopomin.com.br",
    },
    license_info={
        "name": "Auditto",
        "url": "https://auditto.com.br",
    },
    openapi_tags=tags_metadata,
)

app.include_router(auth_router)
logger.info("Router de autenticação incluído com sucesso")

app.include_router(alerta_cliente_router)
logger.info("Router de clientes Alerta Fiscal incluído com sucesso")

app.include_router(omie_cliente_router)
logger.info("Router de clientes Omie incluído com sucesso")

app.include_router(omie_contas_receber_router)
logger.info("Router de contas a receber Omie incluído com sucesso")

app.include_router(omie_contratos_router)
logger.info("Router de contratos Omie incluído com sucesso")

@app.middleware("http")
async def log_requests(request: Request, call_next):
    """Middleware para logar todas as requisições"""
    import time
    start_time = time.time()
    
    logger.info(f"Requisição recebida: {request.method} {request.url.path}")
    logger.debug(f"Headers: {dict(request.headers)}")
    logger.debug(f"Query params: {dict(request.query_params)}")
    
    try:
        response = await call_next(request)
        process_time = time.time() - start_time
        logger.info(
            f"Requisição processada: {request.method} {request.url.path} - "
            f"Status: {response.status_code} - Tempo: {process_time:.3f}s"
        )
        return response
    except Exception as e:
        process_time = time.time() - start_time
        logger.error(
            f"Erro ao processar requisição: {request.method} {request.url.path} - "
            f"Tempo: {process_time:.3f}s - Erro: {e}",
            exc_info=True
        )
        raise

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    """Captura todas as exceções não tratadas e retorna detalhes do erro."""
    from fastapi import HTTPException
    
    if isinstance(exc, HTTPException):
        logger.warning(f"HTTPException: {exc.status_code} - {exc.detail} - Path: {request.url}")
        raise exc
    
    traceback_str = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
    logger.error(
        f"Erro não tratado capturado:\n"
        f"Tipo: {type(exc).__name__}\n"
        f"Mensagem: {str(exc)}\n"
        f"Path: {request.url}\n"
        f"Method: {request.method}\n"
        f"Traceback completo:\n{traceback_str}"
    )
    
    return JSONResponse(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content={
            "error": {
                "code": "INTERNAL_SERVER_ERROR",
                "message": str(exc),
                "details": traceback_str,
                "path": str(request.url),
                "method": request.method,
                "error_type": type(exc).__name__,
            }
        },
    )

@app.get("/health", tags=["Health"], responses={200: {"description": "Serviço operacional"}}, openapi_extra={
    "responses": {
        "200": {
            "content": {"application/json": {"example": {"status": "ok"}}}
        }
    }
})
async def health_check():
    return {"status": "ok"}

@app.get("/scalar", include_in_schema=False)
async def scalar_docs():
    return get_scalar_api_reference(
        openapi_url=app.openapi_url,
        title=f"{app.title} - Scalar",
    )

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    from fastapi.openapi.utils import get_openapi
    schema = get_openapi(
        title=app.title,
        version=app.version,
        description=app.description,
        routes=app.routes,
    )
    components = schema.setdefault("components", {})
    security_schemes = components.setdefault("securitySchemes", {})
    security_schemes["bearerAuth"] = {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Token",
        "description": (
            "Autenticação via Bearer Token. Use um dos seguintes:\n"
            "- **Token Fixo da API**: Token configurado em FIX_API_TOKEN (para rotas protegidas)\n"
            "- **Token do Cliente**: Token retornado no login via `/auth/login` (para rotas de autenticação do cliente)"
        ),
    }
    schema["security"] = [
        {"bearerAuth": []},
    ]

    public_paths = ["/health", "/auth/login"]
    for path, methods in schema.get("paths", {}).items():
        if path in public_paths:
            for method_obj in methods.values():
                method_obj["security"] = []
    app.openapi_schema = schema
    return app.openapi_schema

app.openapi = custom_openapi