<?php

namespace Modules\Payment\Exceptions;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use RuntimeException;

/**
 * Carries a gateway's own error code/message for an unexpected failure that
 * isn't already captured as a typed Failed result (e.g. a malformed
 * response the gateway strategy can't parse into a PaymentResultData/
 * RefundResultData). Never allowed to surface as a raw 500 (domain.md §6,
 * T6.3): a declined/rejected call from the gateway itself is a 422 (client
 * can retry/fix), an unreachable/misbehaving gateway is a 502.
 */
class PaymentGatewayException extends RuntimeException
{
    private function __construct(
        string $message,
        private readonly int $statusCode,
        private readonly ?string $gatewayCode = null,
    ) {
        parent::__construct($message);
    }

    /**
     * The gateway responded but rejected/declined the request — surfaced as
     * 422 since it's a business outcome the caller can act on.
     */
    public static function declined(string $message, ?string $gatewayCode = null): self
    {
        return new self($message, 422, $gatewayCode);
    }

    /**
     * The gateway didn't respond usefully at all (unreachable, malformed
     * payload, unexpected HTTP status) — surfaced as 502, our fault for
     * depending on it, not the caller's.
     */
    public static function unavailable(string $message, ?string $gatewayCode = null): self
    {
        return new self($message, 502, $gatewayCode);
    }

    public function render(Request $request): ?JsonResponse
    {
        if ($request->expectsJson()) {
            return response()->json([
                'message' => $this->getMessage(),
                'gateway_code' => $this->gatewayCode,
            ], $this->statusCode);
        }

        return null;
    }
}
