<?php

namespace App\Services;

use App\Models\Order;
use App\Models\User;
use App\Models\Wallet;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class PaymentProcessingService
{
    /**
     * Process a card payment.
     *
     * @param User $user
     * @param float $amount
     * @param Order $order
     * @param array $flutterWaveResponse
     * @return bool
     * @throws \Exception
     */
    public function processCardPayment(User $user, float $amount, Order $order, array $flutterWaveResponse): bool
    {
        return DB::transaction(function () use ($user, $amount, $order, $flutterWaveResponse) {
            // Mark order as paid
            $order->update([
                'payment_status' => 'paid',
                'payment_method' => 'card',
                'gateway_response' => json_encode($flutterWaveResponse),
                'paid_at' => now(),
            ]);

            // Log transaction
            Log::info("Card payment processed", [
                'user_id' => $user->id,
                'amount' => $amount,
                'order_id' => $order->id,
            ]);

            return true;
        });
    }

    /**
     * Process a mobile money payment.
     *
     * @param User $user
     * @param float $amount
     * @param Order $order
     * @param string $phoneNumber
     * @param array $flutterWaveResponse
     * @return bool
     * @throws \Exception
     */
    public function processMobileMoneyPayment(User $user, float $amount, Order $order, string $phoneNumber, array $flutterWaveResponse): bool
    {
        return DB::transaction(function () use ($user, $amount, $order, $phoneNumber, $flutterWaveResponse) {
            // Mark order as paid
            $order->update([
                'payment_status' => 'paid',
                'payment_method' => 'mobile_money',
                'gateway_response' => json_encode($flutterWaveResponse),
                'paid_at' => now(),
            ]);

            // Log transaction
            Log::info("Mobile money payment processed", [
                'user_id' => $user->id,
                'amount' => $amount,
                'phone' => $phoneNumber,
                'order_id' => $order->id,
            ]);

            return true;
        });
    }

    /**
     * Process a subscription payment.
     *
     * @param User $user
     * @param float $amount
     * @param string $subscriptionPlan
     * @param array $paymentData
     * @return bool
     * @throws \Exception
     */
    public function processSubscriptionPayment(User $user, float $amount, string $subscriptionPlan, array $paymentData): bool
    {
        return DB::transaction(function () use ($user, $amount, $subscriptionPlan, $paymentData) {
            // Create order for subscription
            $order = Order::create([
                'user_id' => $user->id,
                'product_id' => null,
                'type' => 'subscription',
                'subscription_plan' => $subscriptionPlan,
                'quantity' => 1,
                'amount' => $amount,
                'payment_method' => $paymentData['payment_method'] ?? 'unknown',
                'payment_status' => 'paid',
                'shipping_country' => $user->country_code,
                'gateway_response' => json_encode($paymentData),
                'paid_at' => now(),
            ]);

            // Update user subscription status
            $user->update([
                'subscription_plan' => $subscriptionPlan,
                'subscription_active' => true,
                'subscription_started_at' => now(),
                'subscription_expires_at' => $this->calculateSubscriptionExpiry($subscriptionPlan),
            ]);

            // Log transaction
            Log::info("Subscription payment processed", [
                'user_id' => $user->id,
                'amount' => $amount,
                'plan' => $subscriptionPlan,
                'order_id' => $order->id,
            ]);

            return true;
        });
    }

    /**
     * Process a product purchase payment.
     *
     * @param User $user
     * @param float $amount
     * @param Order $order
     * @param array $paymentData
     * @return bool
     * @throws \Exception
     */
    public function processProductPayment(User $user, float $amount, Order $order, array $paymentData): bool
    {
        return DB::transaction(function () use ($user, $amount, $order, $paymentData) {
            // Mark order as paid
            $order->update([
                'payment_status' => 'paid',
                'gateway_response' => json_encode($paymentData),
                'paid_at' => now(),
            ]);

            // Log transaction
            Log::info("Product payment processed", [
                'user_id' => $user->id,
                'amount' => $amount,
                'order_id' => $order->id,
            ]);

            return true;
        });
    }

    /**
     * Handle payment refund.
     *
     * @param User $user
     * @param float $amount
     * @param Order $order
     * @param string $reason
     * @return bool
     * @throws \Exception
     */
    public function refundPayment(User $user, float $amount, Order $order, string $reason = ''): bool
    {
        return DB::transaction(function () use ($user, $amount, $order, $reason) {
            // Update order status
            $order->update([
                'payment_status' => 'refunded',
                'refund_reason' => $reason,
                'refunded_at' => now(),
            ]);

            // Credit wallet using WalletService or fallback
            try {
                if (class_exists(\App\Services\WalletService::class)) {
                    $walletService = app(\App\Services\WalletService::class);
                    $walletService->credit($user, $amount, "Refund for Order #{$order->id}: {$reason}");
                } else {
                    // Fallback: use Wallet model directly
                    $user->wallet()->increment('balance', $amount);
                }
            } catch (\Exception $e) {
                Log::error('Wallet credit failed, using fallback', ['error' => $e->getMessage()]);
                // Ensure wallet is credited even if service fails
                $user->wallet()->increment('balance', $amount);
            }

            // Log transaction
            Log::info("Payment refunded", [
                'user_id' => $user->id,
                'amount' => $amount,
                'order_id' => $order->id,
                'reason' => $reason,
            ]);

            return true;
        });
    }

    /**
     * Handle payment failure.
     *
     * @param User $user
     * @param Order $order
     * @param string $reason
     * @return bool
     */
    public function handlePaymentFailure(User $user, Order $order, string $reason = ''): bool
    {
        return DB::transaction(function () use ($user, $order, $reason) {
            $order->update([
                'payment_status' => 'failed',
                'failure_reason' => $reason,
            ]);

            Log::warning("Payment failed", [
                'user_id' => $user->id,
                'order_id' => $order->id,
                'reason' => $reason,
            ]);

            return true;
        });
    }

    /**
     * Calculate subscription expiry date.
     *
     * @param string $plan
     * @return \DateTime
     */
    private function calculateSubscriptionExpiry(string $plan): \DateTime
    {
        $plans = config('lebon.subscription.plans', []);
        $durationDays = $plans[$plan]['duration_days'] ?? 30;
        return now()->addDays($durationDays);
    }

    /**
     * Verify payment amount matches order.
     *
     * @param Order $order
     * @param float $amount
     * @return bool
     */
    public function verifyPaymentAmount(Order $order, float $amount): bool
    {
        return abs($order->total - $amount) < 0.01; // Allow 0.01 XOF difference for rounding
    }

    /**
     * Log payment event for audit trail.
     *
     * @param string $eventType
     * @param User $user
     * @param Order|null $order
     * @param float $amount
     * @param array $data
     * @return void
     */
    public function logPaymentEvent(string $eventType, User $user, ?Order $order, float $amount, array $data = []): void
    {
        Log::info("Payment event: {$eventType}", array_merge([
            'user_id' => $user->id,
            'order_id' => $order?->id,
            'amount' => $amount,
            'timestamp' => now(),
        ], $data));
    }
}
