<?php

namespace App\Modules\Payment\Flutterwave;

use App\Core\Payment\AbstractPayment;

class Flutterwave extends AbstractPayment
{
    protected $apiUrl;

    public function __construct(array $config = [])
    {
        parent::__construct($config);
        $this->apiUrl = 'https://api.flutterwave.com/v3';
    }

    /**
     * Validate payment parameters before processing
     */
    public function attemptPayment(array $params)
    {
        $requiredParams = ['amount', 'currency', 'email'];

        foreach ($requiredParams as $param) {
            if (! isset($params[$param]) || empty($params[$param])) {
                return [
                    'status' => 'error',
                    'message' => __('admin/modules.flutterwave_missing_parameter', ['param' => $param]),
                    'data' => [],
                ];
            }
        }

        if ($params['amount'] <= 0) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.flutterwave_invalid_amount'),
                'data' => [],
            ];
        }

        return [
            'status' => 'ready',
            'message' => __('admin/modules.flutterwave_ready'),
            'data' => [
                'amount' => $params['amount'],
                'email' => $params['email'],
                'currency' => strtoupper($params['currency']),
            ],
        ];
    }

    /**
     * Initialize a payment via Flutterwave Standard API
     * POST /payments with redirect flow
     */
    public function makePayment(array $params)
    {
        $currency = strtoupper($params['currency'] ?? $this->getConfig('currency', 'NGN'));

        $paymentData = [
            'tx_ref' => $params['tx_ref'] ?? $params['reference'] ?? $params['order_id'] ?? $this->generateReference(),
            'amount' => $params['amount'],
            'currency' => $currency,
            'redirect_url' => $params['redirect_url'] ?? $params['callback_url'] ?? $params['success_url'] ?? '',
            'customer' => [
                'email' => $params['email'],
                'name' => $params['name'] ?? $params['customer_name'] ?? '',
                'phonenumber' => $params['phonenumber'] ?? $params['phone'] ?? '',
            ],
            'customizations' => [
                'title' => $params['title'] ?? $this->getConfig('display_name', 'Payment'),
                'description' => $params['description'] ?? '',
                'logo' => $params['logo'] ?? $this->getConfig('logo', ''),
            ],
        ];

        if (isset($params['meta'])) {
            $paymentData['meta'] = $params['meta'];
        }

        if (isset($params['payment_options'])) {
            $paymentData['payment_options'] = $params['payment_options'];
        }

        $response = $this->callApi($this->apiUrl . '/payments', 'POST', $paymentData);

        if ($response['http_code'] === 200 && ($response['response']['status'] ?? '') === 'success') {
            $data = $response['response']['data'] ?? [];

            return [
                'status' => 'success',
                'message' => __('admin/modules.flutterwave_payment_initialized'),
                'data' => [
                    'payment_link' => $data['link'] ?? '',
                    'tx_ref' => $paymentData['tx_ref'],
                ],
                'payment_url' => $data['link'] ?? '',
            ];
        }

        $errorMessage = $response['response']['message']
            ?? __('admin/modules.flutterwave_payment_init_failed');

        return [
            'status' => 'error',
            'message' => $errorMessage,
            'data' => [],
        ];
    }

    /**
     * Verify transaction via Flutterwave Verify Transaction API
     * GET /transactions/{id}/verify
     * Checks data.status=successful and validates amount/currency match
     */
    public function handlePaymentCallback(array $params)
    {
        $transactionId = $params['transaction_id'] ?? $params['id'] ?? null;

        if (! $transactionId) {
            return [
                'status' => 'failed',
                'message' => __('admin/modules.flutterwave_missing_transaction_id'),
                'data' => [],
            ];
        }

        // Webhook signature: fail-CLOSED. Flutterwave classic sends a
        // 'verif-hash' header == the configured Secret Hash (plain equality);
        // the signed variant sends 'flutterwave-signature' = base64(HMAC-SHA256(rawBody)).
        // If a webhook signature header is PRESENT it MUST verify (else reject).
        // A redirect-return (no signature header) is trusted only via the
        // authenticated verify GET re-query below — a forged callback cannot
        // fake success without a real Flutterwave transaction_id.
        $verifHash = $this->resolveWebhookSignature($params);
        if ($verifHash !== null && ! $this->verifyWebhook($this->resolveRawBody($params), $verifHash)) {
            return [
                'status' => 'failed',
                'message' => __('admin/modules.flutterwave_webhook_signature_mismatch'),
                'data' => [],
            ];
        }

        // Verify transaction via API (authenticated trust anchor)
        $response = $this->callApi($this->apiUrl . '/transactions/' . rawurlencode($transactionId) . '/verify', 'GET');

        if ($response['http_code'] === 200 && ($response['response']['status'] ?? '') === 'success') {
            $data = $response['response']['data'] ?? [];
            $flutterwaveStatus = $data['status'] ?? '';
            $mappedStatus = $this->mapFlutterwaveStatus($flutterwaveStatus);

            // Validate amount and currency match if expected values are provided
            if ($mappedStatus === 'success') {
                if (isset($params['expected_amount']) && (float) $data['amount'] !== (float) $params['expected_amount']) {
                    return [
                        'status' => 'failed',
                        'message' => __('admin/modules.flutterwave_amount_mismatch'),
                        'data' => [
                            'expected_amount' => $params['expected_amount'],
                            'charged_amount' => $data['amount'] ?? 0,
                        ],
                    ];
                }

                if (isset($params['expected_currency']) && strtoupper($data['currency'] ?? '') !== strtoupper($params['expected_currency'])) {
                    return [
                        'status' => 'failed',
                        'message' => __('admin/modules.flutterwave_currency_mismatch'),
                        'data' => [
                            'expected_currency' => $params['expected_currency'],
                            'charged_currency' => $data['currency'] ?? '',
                        ],
                    ];
                }
            }

            return [
                'status' => $mappedStatus,
                'message' => __('admin/modules.flutterwave_payment_status_' . $mappedStatus),
                'transaction_id' => $data['id'] ?? '',
                'data' => [
                    'tx_ref' => $data['tx_ref'] ?? '',
                    'flw_ref' => $data['flw_ref'] ?? '',
                    'flutterwave_status' => $flutterwaveStatus,
                    'amount' => $data['amount'] ?? 0,
                    'currency' => $data['currency'] ?? '',
                    'payment_type' => $data['payment_type'] ?? '',
                    'charged_amount' => $data['charged_amount'] ?? 0,
                    'created_at' => $data['created_at'] ?? '',
                    'customer_email' => $data['customer']['email'] ?? '',
                ],
            ];
        }

        return [
            'status' => 'failed',
            'message' => $response['response']['message']
                ?? __('admin/modules.flutterwave_payment_verification_failed'),
            'data' => [],
        ];
    }

    /**
     * Refund a transaction via Flutterwave Refunds API
     * POST /transactions/{id}/refund
     */
    public function refundPayment(array $params)
    {
        $transactionId = $params['transaction_id'] ?? null;

        if (! $transactionId) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.flutterwave_missing_transaction_id'),
                'data' => [],
            ];
        }

        $refundData = [];

        if (isset($params['amount'])) {
            $refundData['amount'] = $params['amount'];
        }

        $response = $this->callApi($this->apiUrl . '/transactions/' . rawurlencode($transactionId) . '/refund', 'POST', $refundData);

        if ($response['http_code'] === 200 && ($response['response']['status'] ?? '') === 'success') {
            $data = $response['response']['data'] ?? [];

            return [
                'status' => 'success',
                'message' => __('admin/modules.flutterwave_refund_success'),
                'data' => [
                    'refund_id' => $data['id'] ?? '',
                    'amount_refunded' => $data['amount_refunded'] ?? 0,
                    'flutterwave_status' => $data['status'] ?? '',
                    'tx_ref' => $data['tx_ref'] ?? '',
                ],
            ];
        }

        $errorMessage = $response['response']['message']
            ?? __('admin/modules.flutterwave_refund_failed');

        return [
            'status' => 'error',
            'message' => $errorMessage,
            'data' => [],
        ];
    }

    /**
     * Generate a shareable payment link. Flutterwave v3 has NO reusable
     * /v3/payment-links create API — the canonical way to produce a link in v3
     * is POST /v3/payments which returns data.link. Delegate to makePayment.
     */
    public function generatePaymentLink(array $params)
    {
        if (empty($params['email'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.flutterwave_missing_parameter', ['param' => 'email']),
                'data' => [],
            ];
        }

        $result = $this->makePayment($params);

        if (($result['status'] ?? '') === 'success') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.flutterwave_payment_link_created'),
                'data' => [
                    'payment_url' => $result['payment_url'] ?? ($result['data']['payment_link'] ?? ''),
                    'tx_ref' => $result['data']['tx_ref'] ?? '',
                ],
                'payment_url' => $result['payment_url'] ?? ($result['data']['payment_link'] ?? ''),
            ];
        }

        return [
            'status' => 'error',
            'message' => $result['message'] ?? __('admin/modules.flutterwave_payment_link_failed'),
            'data' => [],
        ];
    }

    /**
     * Test API connection by fetching transactions
     * GET /transactions?per_page=1
     */
    public function testConnection(array $params = [])
    {
        $response = $this->callApi($this->apiUrl . '/transactions?per_page=1', 'GET');

        if ($response['http_code'] === 200 && ($response['response']['status'] ?? '') === 'success') {
            return [
                'status' => 'success',
                'message' => __('admin/modules.flutterwave_connection_success'),
                'data' => [],
            ];
        }

        $errorMessage = $response['response']['message']
            ?? __('admin/modules.flutterwave_connection_failed');

        return [
            'status' => 'error',
            'message' => $errorMessage,
            'data' => [],
        ];
    }

    /**
     * Validate module configuration
     */
    public function validateConfig()
    {
        if (empty($this->getConfig('secret_key'))) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.flutterwave_secret_key_required'),
            ];
        }

        if (empty($this->getConfig('public_key'))) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.flutterwave_public_key_required'),
            ];
        }

        return [
            'status' => 'success',
            'message' => __('admin/modules.flutterwave_config_valid'),
        ];
    }

    /**
     * Supported features
     */
    public function getFeatures(): array
    {
        return [
            'refund' => true,
            '3d_secure' => false,
            'save_card' => false,
            'recurring' => false,
            'fraud_check' => false,
        ];
    }

    /**
     * Get configuration fields for admin panel
     */
    public function getConfigFields(): array
    {
        return array_merge(parent::getConfigFields(), [
            'public_key' => [
                'type' => 'text',
                'label' => 'Public Key',
                'description' => 'Flutterwave public key (starts with FLWPUBK_)',
                'required' => true,
                'value' => '',
                'placeholder' => 'FLWPUBK_TEST-...',
            ],
            'secret_key' => [
                'type' => 'password',
                'label' => 'Secret Key',
                'description' => 'Flutterwave secret key (starts with FLWSECK_)',
                'required' => true,
                'value' => '',
                'placeholder' => 'FLWSECK_TEST-...',
            ],
            'encryption_key' => [
                'type' => 'password',
                'label' => 'Encryption Key',
                'description' => 'Flutterwave encryption key for direct card charges',
                'required' => false,
                'value' => '',
                'placeholder' => 'FLWSECK_TEST...',
            ],
            'webhook_secret' => [
                'type' => 'password',
                'label' => 'Secret Hash',
                'description' => 'Flutterwave dashboard "Secret Hash" — used to verify webhook signatures (verif-hash / flutterwave-signature)',
                'required' => false,
                'value' => '',
                'placeholder' => 'Enter Secret Hash',
            ],
        ]);
    }

    /**
     * Override default headers for Bearer token authentication
     */
    protected function getDefaultHeaders()
    {
        return [
            'Content-Type: application/json',
            'Accept: application/json',
            'User-Agent: ProCP/1.0 Payment Gateway Module',
            'Authorization: Bearer ' . $this->getConfig('secret_key', ''),
        ];
    }

    /**
     * Verify a Flutterwave webhook signature. Fail-CLOSED via secureCompare().
     * Classic: 'verif-hash' header == configured Secret Hash (plain equality).
     * Signed:  'flutterwave-signature' header == base64(HMAC-SHA256(rawBody)).
     * Accepts either representation against the configured secret.
     */
    public function verifyWebhook(string $rawBody, string $signature): bool
    {
        $secret = (string) $this->getConfig('webhook_secret', '');

        if ($secret === '' || $signature === '') {
            return false;
        }

        // Classic verif-hash: the header IS the configured secret hash.
        if ($this->secureCompare($secret, $signature)) {
            return true;
        }

        // Signed variant: base64(HMAC-SHA256(rawBody, secret)).
        $expected = base64_encode($this->hmac('sha256', $rawBody, $secret, true));

        return $this->secureCompare($expected, $signature);
    }

    /**
     * Extract the webhook signature header from callback params or the HTTP
     * request. Returns null when no webhook signature header is present
     * (redirect-return path — anchored by the authenticated verify GET).
     */
    private function resolveWebhookSignature(array $params): ?string
    {
        foreach (['verif_hash', 'verif-hash', 'signature', 'flutterwave_signature', 'flutterwave-signature'] as $key) {
            if (! empty($params[$key])) {
                return (string) $params[$key];
            }
        }

        if (function_exists('request') && ($req = request()) !== null) {
            foreach (['verif-hash', 'flutterwave-signature'] as $header) {
                $val = $req->header($header);
                if (! empty($val)) {
                    return (string) $val;
                }
            }
        }

        return null;
    }

    /**
     * Resolve the raw request body used for the signed-variant HMAC.
     */
    private function resolveRawBody(array $params): string
    {
        if (! empty($params['payload'])) {
            return is_string($params['payload']) ? $params['payload'] : json_encode($params['payload']);
        }

        if (function_exists('request') && ($req = request()) !== null) {
            return (string) $req->getContent();
        }

        return '';
    }

    /**
     * Map Flutterwave payment status to internal status
     *
     * Flutterwave statuses: successful, failed, pending
     * Internal statuses: success, failed, pending
     */
    private function mapFlutterwaveStatus(string $flutterwaveStatus): string
    {
        return match ($flutterwaveStatus) {
            'successful' => 'success',
            'failed' => 'failed',
            'pending' => 'pending',
            default => 'failed',
        };
    }

    /**
     * Generate a unique transaction reference
     */
    private function generateReference(): string
    {
        return 'procp_' . bin2hex(random_bytes(10));
    }

    public function getSupportedFeatures(): array
    {
        return $this->getFeatures();
    }
}
