from __future__ import annotations

from typing import Any, Dict
from fastapi import APIRouter, Body, Depends, Query, status, Request, HTTPException

from src.core.deps import get_pagamentos_service, get_mercadopago_service, require_api_key
from src.modules.pagamentos.schemas import PagamentoCreate, PagamentoOut, PagamentoUpdate
from src.modules.pagamentos.service import PagamentosService
from src.modules.pagamentos.mercadopago_service import (
    MercadoPagoService,
    MercadoPagoPaymentResponse,
    MercadoPagoPreferenceRequest,
    MercadoPagoPreferenceResponse,
    MercadoPagoSplitPreferenceRequest,
)

router = APIRouter(prefix="/api/v1/pagamentos", tags=["Pagamentos"])


MERCADOPAGO_WEBHOOK_EXAMPLE: Dict[str, Any] = {
    "id": 1234567890,
    "live_mode": True,
    "type": "payment",
    "date_created": "2015-03-25T10:04:58.396-04:00",
    "user_id": 44444,
    "api_version": "v1",
    "action": "payment.created",
    "data": {
        "id": "999999999"
    }
}


@router.get(
    "",
    summary="List pagamentos",
    description="Return a paginated list of pagamentos with optional filtering, sorting, and search.",
    response_model=dict,
    responses={
        status.HTTP_200_OK: {
            "description": "Successful response",
            "content": {
                "application/json": {
                    "example": {
                        "page": 1,
                        "limit": 20,
                        "total": 2,
                        "items": [
                            {
                                "id": "pay_1",
                                "status": "pendente",
                                "metodo": "pix",
                                "valor": 89.9,
                                "pedidos": "ped_1",
                                "createdAt": "2025-10-01T12:00:00.000Z",
                                "updatedAt": "2025-10-01T12:00:00.000Z",
                            },
                            {
                                "id": "pay_2",
                                "status": "pago",
                                "metodo": "cartao",
                                "valor": 150.0,
                                "pedidos": "ped_2",
                                "createdAt": "2025-10-01T13:00:00.000Z",
                                "updatedAt": "2025-10-01T13:00:00.000Z",
                            },
                        ],
                    }
                }
            },
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "Invalid request parameters",
            "content": {
                "application/json": {
                    "example": {"detail": "Invalid sort field."}
                }
            },
        },
    },
)
async def list_pagamentos(
    page: int = Query(1, ge=1),
    limit: int | None = Query(None, ge=1, le=100),
    q: str | None = Query(None, min_length=1),
    sort: str | None = Query(None),
    order: str | None = Query(None, pattern="^(?i)(asc|desc)$"),
    _: None = Depends(require_api_key),
    service: PagamentosService = Depends(get_pagamentos_service),
) -> dict:
    normalized_order = order.lower() if order else None
    normalized_sort = sort if sort in {"status", "metodo", "valor", "$createdAt"} else sort
    return await service.list(page=page, limit=limit, q=q, sort=normalized_sort, order=normalized_order)


@router.get(
    "/{pagamento_id}",
    summary="Retrieve pagamento",
    description="Fetch a single pagamento by its identifier, including audit metadata.",
    response_model=PagamentoOut,
    responses={
        status.HTTP_200_OK: {
            "description": "Pagamento details",
            "content": {
                "application/json": {
                    "example": {
                        "id": "pay_1",
                        "status": "pendente",
                        "metodo": "pix",
                        "valor": 89.9,
                        "pedidos": "ped_1",
                        "createdAt": "2025-10-01T12:00:00.000Z",
                        "updatedAt": "2025-10-01T12:00:00.000Z",
                    }
                }
            },
        },
        status.HTTP_404_NOT_FOUND: {
            "description": "Pagamento not found",
            "content": {"application/json": {"example": {"detail": "Payment not found."}}},
        },
    },
)
async def get_pagamento(
    pagamento_id: str,
    _: None = Depends(require_api_key),
    service: PagamentosService = Depends(get_pagamentos_service),
) -> PagamentoOut:
    return await service.get(pagamento_id)


@router.post(
    "/mercadopago/preference/test",
    summary="Testar preferência de pagamento (sem autenticação)",
    description="Endpoint de teste para criar uma preferência de pagamento no Mercado Pago sem autenticação.",
    response_model=MercadoPagoPreferenceResponse,
    status_code=status.HTTP_201_CREATED,
)
async def test_mercadopago_preference(
    preference_data: MercadoPagoPreferenceRequest,
    mp_service: MercadoPagoService = Depends(get_mercadopago_service),
) -> MercadoPagoPreferenceResponse:
    """Criar uma preferência de pagamento no Mercado Pago (endpoint de teste)."""
    try:
        preference = await mp_service.create_preference(preference_data)
        return preference
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Erro ao criar preferência: {str(e)}"
        )


@router.post(
    "/mercadopago/split/preference",
    summary="Criar preferência de pagamento com split",
    description=(
        "Cria uma preferência do Mercado Pago configurada com regras de split para repassar "
        "valores automaticamente entre múltiplos recebedores."
    ),
    response_model=MercadoPagoPreferenceResponse,
    status_code=status.HTTP_201_CREATED,
)
async def create_mercadopago_split_preference(
    preference_data: MercadoPagoSplitPreferenceRequest,
    mp_service: MercadoPagoService = Depends(get_mercadopago_service),
) -> MercadoPagoPreferenceResponse:
    try:
        preference = await mp_service.create_split_preference(preference_data)
        return preference
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Erro ao criar preferência com split: {str(e)}",
        )


@router.post(
    "",
    summary="Create pagamento",
    description="Create a new pagamento ensuring audit metadata retrieval.",
    response_model=PagamentoOut,
    status_code=status.HTTP_201_CREATED,
    responses={
        status.HTTP_201_CREATED: {
            "description": "Pagamento created",
            "content": {
                "application/json": {
                    "example": {
                        "id": "pay_3",
                        "status": "pendente",
                        "metodo": "pix",
                        "valor": 49.9,
                        "pedidos": "ped_3",
                        "createdAt": "2025-10-01T14:00:00.000Z",
                        "updatedAt": "2025-10-01T14:00:00.000Z",
                    }
                }
            },
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "Invalid payload",
            "content": {"application/json": {"example": {"detail": "metodo cannot be empty."}}},
        },
    },
)
async def create_pagamento(
    payload: PagamentoCreate,
    _: None = Depends(require_api_key),
    service: PagamentosService = Depends(get_pagamentos_service),
) -> PagamentoOut:
    return await service.create(payload)


@router.patch(
    "/{pagamento_id}",
    summary="Update pagamento",
    description="Update an existing pagamento partially, validating provided data when present.",
    response_model=PagamentoOut,
    responses={
        status.HTTP_200_OK: {
            "description": "Pagamento updated",
            "content": {
                "application/json": {
                    "example": {
                        "id": "pay_1",
                        "status": "pago",
                        "metodo": "cartao",
                        "valor": 89.9,
                        "pedidos": "ped_1",
                        "createdAt": "2025-10-01T12:00:00.000Z",
                        "updatedAt": "2025-10-01T15:00:00.000Z",
                    }
                }
            },
        },
        status.HTTP_404_NOT_FOUND: {
            "description": "Pagamento not found",
            "content": {"application/json": {"example": {"detail": "Payment not found."}}},
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "Invalid payload",
            "content": {"application/json": {"example": {"detail": "metodo cannot be empty."}}},
        },
    },
)
async def update_pagamento(
    pagamento_id: str,
    payload: PagamentoUpdate,
    _: None = Depends(require_api_key),
    service: PagamentosService = Depends(get_pagamentos_service),
) -> PagamentoOut:
    return await service.update(pagamento_id, payload)


@router.delete(
    "/{pagamento_id}",
    summary="Delete pagamento",
    description="Remove a pagamento from the system.",
    status_code=status.HTTP_204_NO_CONTENT,
    responses={
        status.HTTP_204_NO_CONTENT: {"description": "Pagamento removed"},
        status.HTTP_404_NOT_FOUND: {
            "description": "Pagamento not found",
            "content": {"application/json": {"example": {"detail": "Payment not found."}}},
        },
    },
)
async def delete_pagamento(
    pagamento_id: str,
    _: None = Depends(require_api_key),
    service: PagamentosService = Depends(get_pagamentos_service),
) -> None:
    await service.delete(pagamento_id)


# Endpoints específicos do Mercado Pago
@router.post(
    "/mercadopago/preference",
    summary="Criar preferência de pagamento",
    description="Cria uma preferência de pagamento no Mercado Pago para processar transações.",
    response_model=MercadoPagoPreferenceResponse,
    status_code=status.HTTP_201_CREATED,
    responses={
        status.HTTP_201_CREATED: {
            "description": "Preferência criada com sucesso",
            "content": {
                "application/json": {
                    "example": {
                        "id": "123456789-abcd-efgh-ijkl-123456789012",
                        "init_point": "https://www.mercadopago.com.br/checkout/v1/redirect?pref_id=123456789-abcd-efgh-ijkl-123456789012",
                        "sandbox_init_point": "https://sandbox.mercadopago.com.br/checkout/v1/redirect?pref_id=123456789-abcd-efgh-ijkl-123456789012",
                        "collector_id": 123456789,
                        "client_id": "1234567890123456",
                        "date_created": "2025-01-01T12:00:00.000-04:00",
                        "last_updated": "2025-01-01T12:00:00.000-04:00"
                    }
                }
            },
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "Dados inválidos para criação da preferência",
            "content": {"application/json": {"example": {"detail": "Items são obrigatórios."}}},
        },
    },
)
async def create_mercadopago_preference(
    preference_data: MercadoPagoPreferenceRequest,
    _: None = Depends(require_api_key),
    mp_service: MercadoPagoService = Depends(get_mercadopago_service),
) -> MercadoPagoPreferenceResponse:
    return await mp_service.create_preference(preference_data)


@router.post(
    "/mercadopago/webhook",
    summary="Webhook do Mercado Pago",
    description="Endpoint para receber notificações de pagamento do Mercado Pago.",
    status_code=status.HTTP_200_OK,
    responses={
        status.HTTP_200_OK: {
            "description": "Webhook processado com sucesso",
            "content": {
                "application/json": {
                    "example": {
                        "status": "processed",
                        "payment_id": "123456789",
                        "external_reference": "pedido_123"
                    }
                }
            },
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "Webhook inválido",
            "content": {"application/json": {"example": {"detail": "Dados do webhook inválidos."}}},
        },
    },
)
async def mercadopago_webhook(
    request: Request,
    payload: Dict[str, Any] = Body(
        ...,
        example=MERCADOPAGO_WEBHOOK_EXAMPLE,
        description=(
            "Payload padrão enviado pelo Mercado Pago em notificações webhook. "
            "Consulte a documentação oficial para detalhes completos."
        ),
    ),
    mp_service: MercadoPagoService = Depends(get_mercadopago_service),
    pagamentos_service: PagamentosService = Depends(get_pagamentos_service),
) -> Dict[str, Any]:
    try:
        # Obtém o corpo da requisição
        body = await request.body()
        webhook_data = payload
        
        # Valida a assinatura (opcional, mas recomendado)
        signature = request.headers.get("x-signature", "")
        if not mp_service.validate_webhook_signature(body.decode(), signature):
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Assinatura do webhook inválida"
            )
        
        # Processa o webhook
        processed_data = await mp_service.process_webhook(webhook_data)
        
        # Se for um pagamento, atualiza o status no sistema
        if processed_data.get("type") == "payment":
            external_reference = processed_data.get("external_reference")
            if external_reference:
                try:
                    # Busca o pagamento pelo external_reference (que pode ser o ID do pedido)
                    mp_status = processed_data.get("status")
                    internal_status = mp_service.get_payment_status_mapping(mp_status)
                    
                    # Atualiza o status do pagamento
                    # Nota: Aqui você precisaria implementar a lógica para encontrar
                    # o pagamento pelo external_reference e atualizá-lo
                    
                    return {
                        "status": "processed",
                        "payment_id": processed_data.get("payment_id"),
                        "external_reference": external_reference,
                        "new_status": internal_status
                    }
                except Exception as e:
                    # Log do erro, mas não falha o webhook
                    import logging
                    logging.error(f"Erro ao atualizar pagamento: {str(e)}")
        
        return {"status": "received", "type": processed_data.get("type")}
        
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Erro ao processar webhook: {str(e)}"
        )


@router.get(
    "/mercadopago/payment/{payment_id}",
    summary="Buscar pagamento no Mercado Pago",
    description="Busca informações detalhadas de um pagamento específico no Mercado Pago.",
    response_model=MercadoPagoPaymentResponse,
    responses={
        status.HTTP_200_OK: {
            "description": "Dados do pagamento",
            "content": {
                "application/json": {
                    "example": {
                        "id": 123456789,
                        "status": "approved",
                        "transaction_amount": 100.0,
                        "payment_method_id": "pix",
                        "external_reference": "pedido_123"
                    }
                }
            },
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "Identificador inválido",
            "content": {"application/json": {"example": {"detail": "ID do pagamento inválido."}}},
        },
        status.HTTP_404_NOT_FOUND: {
            "description": "Pagamento não encontrado",
            "content": {"application/json": {"example": {"detail": "Pagamento não encontrado."}}},
        },
    },
)
async def get_mercadopago_payment(
    payment_id: str,
    _: None = Depends(require_api_key),
    mp_service: MercadoPagoService = Depends(get_mercadopago_service),
) -> MercadoPagoPaymentResponse:
    try:
        normalized_payment_id = int(payment_id)
    except (TypeError, ValueError):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="ID do pagamento inválido."
        )

    try:
        payment = await mp_service.get_payment(normalized_payment_id)
    except HTTPException:
        raise
    except Exception as exc:  # pragma: no cover - comportamento defensivo
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"Erro ao consultar pagamento: {str(exc)}"
        ) from exc

    return payment


@router.get(
    "/mercadopago/payment/by-reference/{external_reference}",
    summary="Buscar pagamentos por external_reference",
    description="Busca pagamentos no Mercado Pago usando a referência externa. Útil para fazer polling e detectar quando o pagamento PIX é aprovado.",
    responses={
        status.HTTP_200_OK: {
            "description": "Status do pagamento",
            "content": {
                "application/json": {
                    "example": {
                        "has_payment": True,
                        "latest_payment": {
                            "id": 123456789,
                            "status": "approved",
                            "transaction_amount": 100.0,
                            "payment_method_id": "pix",
                            "external_reference": "pedido_123"
                        },
                        "is_approved": True,
                        "count": 1
                    }
                }
            },
        },
    },
)
async def get_mercadopago_payments_by_reference(
    external_reference: str,
    _: None = Depends(require_api_key),
    mp_service: MercadoPagoService = Depends(get_mercadopago_service),
) -> Dict[str, Any]:
    """
    Buscar pagamentos por external_reference. 
    Útil para verificar status do pagamento e fazer polling.
    Retorna o pagamento mais recente e indica se está aprovado.
    """
    try:
        from src.modules.pagamentos.mercadopago_service import MercadoPagoPaymentResponse
        
        payments = await mp_service.search_payments_by_reference(external_reference)
        
        if not payments:
            return {
                "has_payment": False,
                "latest_payment": None,
                "is_approved": False,
                "count": 0,
                "message": "Nenhum pagamento encontrado para esta referência"
            }
        
        # Pega o pagamento mais recente (já vem ordenado por data)
        latest_payment = payments[0]
        latest_dict = latest_payment.model_dump(exclude_none=True)
        
        return {
            "has_payment": True,
            "latest_payment": latest_dict,
            "is_approved": latest_payment.status == "approved",
            "status": latest_payment.status,
            "count": len(payments),
            "all_payments": [p.model_dump(exclude_none=True) for p in payments] if len(payments) > 1 else None
        }
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Erro ao buscar pagamentos: {str(e)}"
        )