<?php

namespace App\PaymentGateways\Braintree;

use AllowDynamicProperties;
use App\Contracts\PaymentGatewayContract;
use App\Models\Order;
use App\Services\OrderService;
use Braintree\Gateway;

#[AllowDynamicProperties]
class BraintreeGateway implements PaymentGatewayContract
{
    public function __construct(protected OrderService $orderService)
    {
        $this->gateway = new Gateway([
            'environment' => setting('braintree.sandbox_mode') === 'yes' ? 'sandbox' : 'production',
            'merchantId' => setting('braintree.merchant_id'),
            'publicKey' => setting('braintree.public_key'),
            'privateKey' => setting('braintree.private_key'),
        ]);
    }

    public function processPayment(Order $order)
    {
        $nonce = request('braintree_nonce');

        $response = $this->gateway->transaction()->sale([
            'amount' => $order->total,
            'orderId' => $order->id,
            'paymentMethodNonce' => $nonce,
            'options' => [
                'submitForSettlement' => true,
            ],
            'customer' => [
                'firstName' => $order->user->first_name ?? '',
                'lastName' => $order->user->last_name ?? '',
                'email' => $order->user->email ?? '',
            ],
            'billing' => [
                'firstName' => $order->user->billingAddress->first_name ?? '',
                'lastName' => $order->user->billingAddress->last_name ?? '',
                'streetAddress' => $order->user->billingAddress->address ?? '',
                'locality' => $order->user->billingAddress->city ?? '',
                'postalCode' => $order->user->billingAddress->zip ?? '',
            ],
        ]);

        if ($response->success) {
            $transaction = $response->transaction;
            $status = setting('braintree.order_status', getConstant('ORDER_STATUS_PROCESSING'));
            $tx_id = $transaction->id;
            $this->orderService->handlePostPaymentFlow($order, $status);
            $this->orderService->update($order, 'transaction_id', $tx_id);
            $this->orderService->update($order, 'payment_error', null);

            return response()->json(['redirect_url' => route('ch_order_submitted', ['order_id' => $order->encrypted_id])]);
        } else {
            $errorMessages = [];
            foreach ($response->errors->deepAll() as $error) {
                $errorMessages[] = $error->code . ': ' . $error->message;
            }

            $order->update([
                'payment_error' => implode(', ', $errorMessages),
                'status' => getConstant('ORDER_STATUS_FAILED'),
            ]);

            return response()->json([
                'redirect_url' => route('ch_order_failed', ['order_id' => $order->encrypted_id]),
            ]);
        }
    }

    public function completePurchase(Order $order)
    {
        // TODO: Implement completePurchase() method.
    }

    public function processIPN()
    {
        // TODO: Implement processIPN() method.
    }

    public function getToken()
    {
        return $this->gateway->clientToken()->generate();
    }

    public function isConfigured(): bool
    {
        return setting('braintree.enabled') == 'yes'
            &&
            !empty(\setting('braintree.merchant_id')) &&
            !empty(\setting('braintree.public_key')) &&
            !empty(\setting('braintree.private_key'));
    }

    public function renderForm()
    {
        return [
            'id' => $this->getIdentifier(),
        ];
    }

    public function getLabel(): string
    {
        return setting('braintree.title', 'Braintree');
    }

    public function getIdentifier(): string
    {
        return 'braintree';
    }
}
