from typing import Optional
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, HTTPException, Query, Body, status

from src.core.database import get_db
from src.core.auth import require_enterprise_or_front
from src.services.computadores import ComputadorService
from src.schemas.computadores import (
    ComputerCreate, ComputerUpdate, ComputerResponse,)
from src.core.api_responses import (
    build_success_payload, to_schema_dict, SuccessResponse, ErrorResponse)

router = APIRouter(
    prefix="/computadores",
    tags=["Computadores"],
)

computador_service = ComputadorService()


def _get_constraint_error_message(error: IntegrityError) -> str:
    error_parts: list[str] = []
    if hasattr(error, "orig"):
        try:
            orig_args = getattr(error.orig, "args", None)
            if orig_args:
                error_parts.extend([str(a) for a in orig_args])
        except Exception:
            pass
        try:
            error_parts.append(str(error.orig))
        except Exception:
            pass
    try:
        error_parts.append(str(error))
    except Exception:
        pass

    error_str_lower = " ".join(error_parts).lower()

    if ("nomeusuario" in error_str_lower or
            "nome_usuario" in error_str_lower or
            "uq_computadores_nomeusuario_empresa" in error_str_lower):
        return (
            "Já existe um computador cadastrado com este nome de usuário "
            "nesta empresa.")
    elif ("nomehost" in error_str_lower or
            "nome_host" in error_str_lower or
            "uq_computadores_nomehost_empresa" in error_str_lower):
        return "Já existe um computador com este nome de host."
    elif "numeroserie" in error_str_lower or "numero_serie" in error_str_lower:
        return "Já existe um computador cadastrado com este número de série."
    else:
        return "Conflito ao criar/atualizar computador."


@router.post(
    "/criar",
    summary="Criar computador",
    description=(
        "Cria um novo computador vinculado a uma empresa.\n\n"
        "Autenticação: requer token do Front OU token de Empresa\n"
            "ou header X-Enterprise-Token.\n\n"
        "Exemplo cURL:\n\n"
        "```bash\n"
        "curl -X POST 'https://exemplo/computadores/criar' \\\n"
        "  -H 'Authorization: Bearer <TOKEN>' \\\n"
        "  -H 'Content-Type: application/json' \\\n"
        "  -d '{\"empresa_id\":\"id\",\"nome_host\":\"SRV-01\"}'\n"
        "```\n\n"
        "Usando X-Enterprise-Token:\n\n"
        "```bash\n"
        "curl -X POST 'https://exemplo/computadores/criar' \\\n"
        "  -H 'X-Enterprise-Token: <TOKEN_EMPRESA>' \\\n"
        "  -H 'Content-Type: application/json' \\\n"
        "  -d '{\"empresa_id\":\"id\",\"nome_host\":\"SRV-01\"}'\n"
        "```"),
    status_code=status.HTTP_201_CREATED,
    response_model=SuccessResponse,
    responses={
        201:
            {
                "description": "Computador criado com sucesso"
            },
        400:
            {
                "description": "Dados inválidos",
                "model": ErrorResponse
            },
        409:
            {
                "description": "Conflito: Dados duplicados",
                "model": ErrorResponse
            },
        401:
            {
                "description": "Credenciais inválidas ou ausentes",
                "model": ErrorResponse
            },
        500:
            {
                "description": "Erro interno",
                "model": ErrorResponse
            },
    },
    openapi_extra={
        "requestBody": {
            "content": {
                "application/json": {
                    "examples": {
                        "empresa_id": "id",
                        "nome_host": "SRV-01",
                        "sistema_operacional": "Windows 11 Pro",
                        "ram_instalada": 16384}}}},
        "responses": {
            "201": {
                "content": {
                    "application/json": {
                        "examples": {
                            "message": "Computador criado com sucesso",
                            "data": {
                                "id": "1a2bbf80-9a6e-4527-9b7c-13d5b3b3d1f5",
                                "empresa_id": "id",
                                "nome_host": "SRV-01"
                            },
                            "timestamp": "2025-01-01T12:00:00Z"
                        }
                    }
                }
            },
            "400": {
                "content": {
                    "application/json": {
                        "examples": {
                            "error": {
                                "code": "VALIDATION_ERROR",
                                "message": "Dados inválidos"},
                            "timestamp": "2025-01-01T12:00:00Z"}}}},
            "409": {
                "content": {
                    "application/json": {
                        "examples": {
                            "error":
                            {
                                "code": "CONFLICT",
                                "message": "Duplicatas."
                            },
                            "timestamp": "2025-01-01T12:00:00Z"}}}},
            "401": {
                "content": {
                    "application/json": {
                        "examples": {
                            "error": {
                                "code": "AUTH_ERROR",
                                "message": "Credenciais inválidas ou ausentes"
                            },
                            "timestamp": "2025-01-01T12:00:00Z"}}}}}})
async def criar_computador(
    payload: ComputerCreate,
    db: AsyncSession = Depends(get_db),
    _auth=Depends(require_enterprise_or_front),
):
    try:
        obj = await computador_service.criar(db, payload)
    except IntegrityError as e:
        error_message = _get_constraint_error_message(e)
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=error_message
        ) from e
    data = to_schema_dict(ComputerResponse, obj)
    message = f"Computador criado com sucesso (ID: {data.get('id')})"
    return build_success_payload(data=data, message=message)


@router.get(
    "/buscar",
    summary="Listar computadores",
    description=(
        "Retorna computadores, com opção de filtrar por empresa.\n\n"
        "Parâmetros:\n"
        "- empresa_id (query, opcional): filtra pelos computadores.\n\n"
        "Exemplo cURL (sem filtro):\n\n"
            "```bash\n"
        "curl -X GET 'https://exemplo/computadores/buscar'"" \\\n"
        "-H 'Authorization: Bearer <TOKEN>'\n"
        "```\n\n"
        "Com filtro empresa_id:\n\n"
        "```bash\n"
        "curl -X GET 'https://exemplo/computadores/buscar?empresa_id=id' \\\n"
        "  -H 'Authorization: Bearer <TOKEN>'\n"
        "```\n\n"
        "Usando X-Enterprise-Token:\n\n"
        "```bash\n"
        "curl -X GET 'https://exemplo/computadores/buscar?empresa_id=id' \\\n"
        "  -H 'X-Enterprise-Token: <TOKEN_EMPRESA>'\n"
        "```"
    ),
    response_model=SuccessResponse,
    responses={
        200:
            {
                "description": "Lista de computadores"
            },
        401:
            {
                "description": "Credenciais inválidas ou ausentes",
                "model": ErrorResponse
            },
        500:
            {
                "description": "Erro interno",
                "model": ErrorResponse
            },
    },
    openapi_extra={
        "responses": {
            "200": {
                "content": {
                    "application/json": {
                        "examples": {
                            "message": "2 computadores encontrados",
                            "data": [
                                {
                                    "id": "1a2bbf80-9a6e-4527-9b7c",
                                    "empresa_id": "id",
                                    "nome_host": "SRV-01"
                                },
                                {
                                    "id": "2b3c4d5e-6f7a-8b9c-0d1e",
                                    "empresa_id": "id",
                                    "nome_host": "SRV-02"
                                }
                            ],
                            "timestamp": "2025-01-01T12:00:00Z"
                        }
                    }
                }
            },
            "500":
                {
                    "content":
                        {
                            "application/json":
                                {
                                    "examples":
                                        {
                                            "error":
                                                {
                                                    "code": "INTERNA_ERROR",
                                                    "message": "Erro"
                                                },
                                            "timestamp": "2025-01-01T12:00:00Z"
                                            }
                                        }
                                }
                        }
        }
    }
)
async def listar_computadores(
    empresa_id: Optional[str] = Query(
        None,
        description="Filtrar por ID da empresa",
        examples="id",
    ),
    db: AsyncSession = Depends(get_db),
    _auth=Depends(require_enterprise_or_front),
):
    items = await computador_service.listar(db, empresa_id=empresa_id)
    data = [to_schema_dict(ComputerResponse, x) for x in items]
    qtd = len(data)
    if empresa_id:
        sufixo = f" da empresa {empresa_id}"
    else:
        sufixo = ""
    if qtd == 0:
        message = f"Nenhum computador encontrado{sufixo}"
    elif qtd == 1:
        message = f"1 computador encontrado{sufixo}"
    else:
        message = f"{qtd} computadores encontrados{sufixo}"
    return build_success_payload(data=data, message=message)


@router.put(
    "/{computador_id}",
    summary="Atualizar computador",
    description=(
        "Atualiza dados do computador informado por ID.\n\n"
        "Exemplo cURL:\n\n"
        "```bash\n"
        "curl -X PUT 'https://exemplo/computadores/id' \\\n"
        "  -H 'Authorization: Bearer <TOKEN>' \\\n"
        "  -H 'Content-Type: application/json' \\\n"
        "  -d '{\"nome_host\":\"SRV-02\"}'\n"
        "```\n\n"
        "Usando X-Enterprise-Token:\n\n"
        "```bash\n"
        "curl -X PUT 'https://exemplo/computadores/id' \\\n"
        "  -H 'X-Enterprise-Token: <TOKEN_EMPRESA>' \\\n"
        "  -H 'Content-Type: application/json' \\\n"
        "  -d '{\"nome_host\":\"SRV-02\"}'\n"
        "```"),
    response_model=SuccessResponse,
    responses={
        200: {
            "description": "Computador atualizado com sucesso"},
        400: {
            "description": "Dados inválidos",
            "model": ErrorResponse},
        409: {
            "description": "Conflito: dados duplicados",
            "model": ErrorResponse},
        401: {
            "description": "Credenciais inválidas ou ausentes",
            "model": ErrorResponse},
        404: {
            "description": "Computador não encontrado",
            "model": ErrorResponse},
        500: {
            "description": "Erro interno",
            "model": ErrorResponse},
    },
    openapi_extra={
        "responses": {
            "200": {
                "content": {
                    "application/json": {
                        "examples": {
                            "message": "Computador atualizado com sucesso",
                            "data": {
                                "id": "1a2bbf80-9a6e-4527-9b7c-13d5b3b3d1f5",
                                "nome_host": "SRV-02"
                            },
                            "timestamp": "2025-01-01T12:00:00Z"
                        }
                    }
                }
            },
            "409": {
                "content": {
                    "application/json": {
                        "examples": {
                            "error": {
                                "code": "CONFLICT",
                                "message": "Já existe um computador igual."
                            },
                            "timestamp": "2025-01-01T12:00:00Z"}}}},
            "500": {
                "content": {
                    "application/json": {
                        "examples": {
                            "error": {
                                "code": "INTERNAL_SERVER_ERROR",
                                "message": "Erro inesperado"},
                            "timestamp": "2025-01-01T12:00:00Z"}}}}}})
async def atualizar_computador(
    computador_id: str,
    payload: ComputerUpdate,
    db: AsyncSession = Depends(get_db),
        _auth=Depends(require_enterprise_or_front),
):
    try:
        obj = await computador_service.atualizar(db, computador_id, payload)
    except IntegrityError as e:
        error_message = _get_constraint_error_message(e)
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=error_message
        ) from e
    if not obj:
        raise HTTPException(
            status_code=404,
            detail=f"Computador '{computador_id}' não encontrado"
        )
    data = to_schema_dict(ComputerResponse, obj)
    message = f"Computador atualizado com sucesso (ID: {data.get('id')})"
    return build_success_payload(data=data, message=message)


@router.delete(
    "/{computador_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Excluir computador",
    description=("Remove o computador informado por ID. Requer token válido."),
    responses={
        204: {
            "description": "Computador excluído"},
        401: {
            "description": "Credenciais inválidas ou ausentes",
            "model": ErrorResponse},
        404: {
            "description": "Computador não encontrado",
            "model": ErrorResponse},
        500: {
            "description": "Erro interno",
            "model": ErrorResponse},
    },
    openapi_extra={
        "responses": {
            "500": {
                "content": {
                    "application/json": {
                        "examples": {
                            "error": {
                                "code": "INTERNAL_SERVER_ERROR",
                                "message": "Erro inesperado"},
                            "timestamp": "2025-01-01T12:00:00Z"}}}}}})
async def excluir_computador(
    computador_id: str,
    db: AsyncSession = Depends(get_db),
        _auth=Depends(require_enterprise_or_front),
):
    ok = await computador_service.deletar(db, computador_id)
    if not ok:
        raise HTTPException(
            status_code=404,
            detail=f"Computador '{computador_id}' não encontrado")
    return None


@router.post(
    "/heartbeat/{computador_id}",
    summary="Registrar heartbeat do computador",
    description=(
        "Registra um heartbeat do computador para indicar que está online.\n\n"
        "Requer token válido."),
    responses={
        200: {
            "description": "Heartbeat registrado com sucesso"},
        401: {
            "description": "Credenciais inválidas ou ausentes",
            "model": ErrorResponse},
        404: {
            "description": "Computador não encontrado",
            "model": ErrorResponse},
        500: {
            "description": "Erro interno",
            "model": ErrorResponse},
    })
async def post_heartbeat(
    computador_id: str,
    nome_usuario: str = Body(
        ...,
        embed=True,
        description="Nome de usuário do computador"
    ),
    db: AsyncSession = Depends(get_db),
    _auth=Depends(require_enterprise_or_front),
):
    ok = await computador_service.registrar_heartbeat(
        db,
        computador_id,
        nome_usuario
    )
    if not ok:
        raise HTTPException(
            status_code=404,
            detail=f"Computador '{computador_id}' não encontrado")
    return build_success_payload(message="Heartbeat registrado com sucesso")


@router.get(
    "/heartbeat/{computador_id}",
    summary="Listar computadores online",
    description=(
        "Retorna a lista de computadores ativos nos últimos 5 minutos.\n\n"
        "Requer token válido."),
    response_model=SuccessResponse,
    responses={
        200: {
            "description": "status do computador"},
        401: {
            "description": "Credenciais inválidas ou ausentes",
            "model": ErrorResponse},
        500: {
            "description": "Erro interno",
            "model": ErrorResponse},
    })
async def get_heartbeat_computer(
    computador_id: str,
    db: AsyncSession = Depends(get_db),
        _auth=Depends(require_enterprise_or_front),
):
    computador = await computador_service.verificar_heartbeat(
        db,
        computador_id
    )
    status_str = "online" if computador else "offline"
    return build_success_payload(message=f"Status: {status_str}")


@router.get(
    "/computadores-online",
    summary="Listar computadores online",
    description=(
        "Retorna a lista de computadores ativos nos últimos 5 minutos.\n\n"
        "Requer token válido."),
    response_model=SuccessResponse,
    responses={
        200: {
            "description": "Lista de computadores online"},
        401: {
            "description": "Credenciais inválidas ou ausentes",
            "model": ErrorResponse},
        500: {
            "description": "Erro interno",
            "model": ErrorResponse},
    })
async def get_computadores_online(
    db: AsyncSession = Depends(get_db),
        _auth=Depends(require_enterprise_or_front),
):
    computadoresOnline = await computador_service.listar_computadores_online(
        db
    )
    return build_success_payload(data=computadoresOnline)
