<?php

namespace App\Services;

use App\Models\Investment;
use App\Models\PaymentTransaction;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class PaystackService
{
    protected string $secretKey;
    protected string $baseUrl;
    protected string $callbackUrl;

    public function __construct()
    {
        $this->secretKey = config('paystack.secret_key');
        $this->baseUrl = config('paystack.base_url');
        $this->callbackUrl = config('paystack.callback_url');
    }

    /**
     * Initialize a payment transaction
     */
    public function initializeTransaction(Investment $investment): array
    {
        $reference = 'MSL-PAY-' . time() . '-' . strtoupper(Str::random(8));

        $payload = [
            'email' => $investment->email,
            'amount' => (int) ($investment->investment_amount * 100), // Convert to kobo/cents
            'currency' => $investment->currency,
            'reference' => $reference,
            'callback_url' => $this->callbackUrl,
            'metadata' => [
                'investment_id' => $investment->id,
                'investment_reference' => $investment->reference,
                'investor_name' => $investment->investor_name,
                'investment_tier' => $investment->investment_tier,
                'investment_term' => $investment->investment_term,
                'custom_fields' => [
                    [
                        'display_name' => 'Investment Reference',
                        'variable_name' => 'investment_reference',
                        'value' => $investment->reference,
                    ],
                    [
                        'display_name' => 'Investment Tier',
                        'variable_name' => 'tier',
                        'value' => ucfirst($investment->investment_tier),
                    ],
                    [
                        'display_name' => 'Investment Amount',
                        'variable_name' => 'amount',
                        'value' => $investment->currency . ' ' . number_format($investment->investment_amount, 2),
                    ],
                ],
            ],
        ];

        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->secretKey,
            'Content-Type' => 'application/json',
        ])->post($this->baseUrl . '/transaction/initialize', $payload);

        if (!$response->successful()) {
            Log::error('Paystack initialization failed', [
                'investment_id' => $investment->id,
                'response' => $response->json(),
            ]);

            return [
                'success' => false,
                'message' => $response->json()['message'] ?? 'Payment initialization failed',
            ];
        }

        $data = $response->json()['data'];

        // Update investment with payment reference
        $investment->update([
            'payment_reference' => $data['reference'],
            'payment_status' => 'processing',
        ]);

        // Create payment transaction record
        PaymentTransaction::create([
            'investment_id' => $investment->id,
            'paystack_reference' => $data['reference'],
            'amount' => $investment->investment_amount,
            'currency' => $investment->currency,
            'status' => 'pending',
            'ip_address' => request()->ip(),
        ]);

        return [
            'success' => true,
            'authorization_url' => $data['authorization_url'],
            'access_code' => $data['access_code'],
            'reference' => $data['reference'],
        ];
    }

    /**
     * Verify a payment transaction
     */
    public function verifyTransaction(string $reference): array
    {
        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->secretKey,
        ])->get($this->baseUrl . '/transaction/verify/' . $reference);

        if (!$response->successful()) {
            Log::error('Paystack verification failed', [
                'reference' => $reference,
                'response' => $response->json(),
            ]);

            return [
                'success' => false,
                'message' => 'Payment verification failed',
            ];
        }

        $data = $response->json()['data'];

        // Find the payment transaction
        $transaction = PaymentTransaction::where('paystack_reference', $reference)->first();

        if (!$transaction) {
            return [
                'success' => false,
                'message' => 'Transaction not found',
            ];
        }

        if ($data['status'] === 'success') {
            $transaction->markAsSuccessful($data);

            // Update investment
            $investment = $transaction->investment;
            $investment->update([
                'payment_status' => 'confirmed',
                'payment_completed_at' => $data['paid_at'] ?? now(),
                'payment_method' => $data['channel'] ?? null,
                'status' => 'payment_confirmed',
            ]);

            return [
                'success' => true,
                'data' => $data,
                'investment' => $investment,
                'transaction' => $transaction,
            ];
        }

        $transaction->markAsFailed($data);

        return [
            'success' => false,
            'message' => 'Payment was not successful',
            'status' => $data['status'],
        ];
    }

    /**
     * Validate webhook signature
     */
    public function validateWebhookSignature(string $payload, string $signature): bool
    {
        $expectedSignature = hash_hmac('sha512', $payload, $this->secretKey);

        return hash_equals($expectedSignature, $signature);
    }

    /**
     * Initiate a refund
     */
    public function initiateRefund(PaymentTransaction $transaction, ?string $reason = null): array
    {
        $payload = [
            'transaction' => $transaction->paystack_reference,
        ];

        if ($reason) {
            $payload['merchant_note'] = $reason;
        }

        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->secretKey,
            'Content-Type' => 'application/json',
        ])->post($this->baseUrl . '/refund', $payload);

        if (!$response->successful()) {
            Log::error('Paystack refund failed', [
                'transaction_id' => $transaction->id,
                'response' => $response->json(),
            ]);

            return [
                'success' => false,
                'message' => $response->json()['message'] ?? 'Refund failed',
            ];
        }

        $data = $response->json()['data'];

        // Update transaction status
        $transaction->update([
            'status' => 'refunded',
            'paystack_response' => array_merge(
                $transaction->paystack_response ?? [],
                ['refund' => $data]
            ),
        ]);

        // Update investment status
        $transaction->investment->update([
            'payment_status' => 'refunded',
            'status' => 'cancelled',
        ]);

        return [
            'success' => true,
            'data' => $data,
        ];
    }

    /**
     * Initiate a transfer (for dividend payments)
     */
    public function initiateTransfer(
        string $recipientCode,
        float $amount,
        string $reason,
        ?string $reference = null
    ): array {
        $payload = [
            'source' => 'balance',
            'amount' => (int) ($amount * 100),
            'recipient' => $recipientCode,
            'reason' => $reason,
            'reference' => $reference ?? 'DIV-' . time() . '-' . strtoupper(Str::random(6)),
        ];

        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->secretKey,
            'Content-Type' => 'application/json',
        ])->post($this->baseUrl . '/transfer', $payload);

        if (!$response->successful()) {
            Log::error('Paystack transfer failed', [
                'response' => $response->json(),
            ]);

            return [
                'success' => false,
                'message' => $response->json()['message'] ?? 'Transfer failed',
            ];
        }

        return [
            'success' => true,
            'data' => $response->json()['data'],
        ];
    }

    /**
     * Create a transfer recipient
     */
    public function createTransferRecipient(
        string $name,
        string $accountNumber,
        string $bankCode,
        string $currency = 'NGN'
    ): array {
        $payload = [
            'type' => 'nuban',
            'name' => $name,
            'account_number' => $accountNumber,
            'bank_code' => $bankCode,
            'currency' => $currency,
        ];

        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->secretKey,
            'Content-Type' => 'application/json',
        ])->post($this->baseUrl . '/transferrecipient', $payload);

        if (!$response->successful()) {
            return [
                'success' => false,
                'message' => $response->json()['message'] ?? 'Failed to create recipient',
            ];
        }

        return [
            'success' => true,
            'data' => $response->json()['data'],
        ];
    }

    /**
     * List banks
     */
    public function listBanks(string $country = 'nigeria'): array
    {
        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->secretKey,
        ])->get($this->baseUrl . '/bank', [
            'country' => $country,
        ]);

        if (!$response->successful()) {
            return [
                'success' => false,
                'message' => 'Failed to fetch banks',
            ];
        }

        return [
            'success' => true,
            'data' => $response->json()['data'],
        ];
    }
}
