<?php

namespace App\Http\Controllers;

use App\Models\Order;
use App\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;

class PaymentController extends Controller
{
    public function index(Order $order): JsonResponse
    {
        $payments = $order->payments()->orderBy('created_at', 'desc')->get();

        return response()->json([
            'payments' => $payments,
            'total_paid' => $payments->where('status', 'completed')->sum('amount'),
            'remaining_amount' => $order->getRemainingAmount(),
            'is_fully_paid' => $order->isPaid(),
        ]);
    }

    public function store(Request $request, Order $order): JsonResponse
    {
        $request->validate([
            'method' => 'required|in:cash,mpesa,card,bank_transfer',
            'amount' => 'required|numeric|min:0.01',
            'received_amount' => 'nullable|numeric|min:0',
            'mpesa_phone_number' => 'nullable|string|regex:/^\+254[0-9]{9}$/',
            'card_last_four' => 'nullable|string|size:4',
            'card_type' => 'nullable|string|in:visa,mastercard,amex',
            'notes' => 'nullable|string|max:500',
        ]);

        // Validate payment amount doesn't exceed remaining balance
        $remainingAmount = $order->getRemainingAmount();
        if ($request->amount > $remainingAmount) {
            return response()->json([
                'error' => 'Payment amount exceeds remaining balance'
            ], 400);
        }

        DB::beginTransaction();
        try {
            $paymentData = [
                'order_id' => $order->id,
                'method' => $request->method,
                'amount' => $request->amount,
                'status' => 'completed', // For now, all payments are immediately completed
                'notes' => $request->notes,
                'processed_at' => now(),
            ];

            // Handle cash payments
            if ($request->method === 'cash') {
                $receivedAmount = $request->received_amount ?? $request->amount;
                $changeAmount = max(0, $receivedAmount - $request->amount);
                
                $paymentData['received_amount'] = $receivedAmount;
                $paymentData['change_amount'] = $changeAmount;
            }

            // Handle M-Pesa payments
            if ($request->method === 'mpesa') {
                if ($request->mpesa_phone_number) {
                    $paymentData['mpesa_phone_number'] = $request->mpesa_phone_number;
                }
                // In a real implementation, you would initiate STK Push here
                $paymentData['mpesa_receipt_number'] = 'MPX' . time();
                $paymentData['mpesa_transaction_id'] = 'TXN' . time();
            }

            // Handle card payments
            if ($request->method === 'card') {
                $paymentData['card_last_four'] = $request->card_last_four;
                $paymentData['card_type'] = $request->card_type;
                $paymentData['authorization_code'] = 'AUTH' . time();
            }

            $payment = Payment::create($paymentData);

            // Update order payment status and status if fully paid
            $order = $order->fresh();
            $totalPaid = $order->payments()->where('status', 'completed')->sum('amount');
            
            if ($totalPaid >= $order->total_amount) {
                // Order is fully paid
                $order->update([
                    'payment_status' => 'paid',
                    'status' => 'completed', 
                    'completed_at' => now()
                ]);
                
                // Make table available if dine-in
                if ($order->type === 'dine_in' && $order->table) {
                    $order->table->makeAvailable();
                }
            } else {
                // Update to partial if there are payments but not fully paid
                $order->update(['payment_status' => 'partial']);
            }

            DB::commit();

            return response()->json([
                'message' => 'Payment processed successfully',
                'payment' => $payment,
                'order' => $order->fresh(),
                'remaining_amount' => $order->getRemainingAmount(),
                'is_fully_paid' => $order->isPaid(),
            ], 201);

        } catch (\Exception $e) {
            DB::rollback();
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }

    public function update(Request $request, Payment $payment): JsonResponse
    {
        $request->validate([
            'status' => 'required|in:pending,completed,failed,refunded',
            'notes' => 'nullable|string|max:500',
        ]);

        $payment->update([
            'status' => $request->status,
            'notes' => $request->notes,
            'processed_at' => $request->status === 'completed' ? now() : $payment->processed_at,
        ]);

        return response()->json([
            'message' => 'Payment updated successfully',
            'payment' => $payment,
        ]);
    }

    public function refund(Request $request, Payment $payment): JsonResponse
    {
        if (!$payment->canBeRefunded()) {
            return response()->json(['error' => 'Payment cannot be refunded'], 400);
        }

        $request->validate([
            'reason' => 'required|string|max:500',
        ]);

        DB::beginTransaction();
        try {
            $payment->update([
                'status' => 'refunded',
                'notes' => ($payment->notes ? $payment->notes . ' | ' : '') . 'Refunded: ' . $request->reason,
            ]);

            // Create a negative payment record for the refund
            Payment::create([
                'order_id' => $payment->order_id,
                'payment_reference' => 'REF-' . $payment->payment_reference,
                'method' => $payment->method,
                'status' => 'completed',
                'amount' => -$payment->amount,
                'notes' => 'Refund for payment: ' . $payment->payment_reference,
                'processed_at' => now(),
            ]);

            DB::commit();

            return response()->json(['message' => 'Payment refunded successfully']);

        } catch (\Exception $e) {
            DB::rollback();
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }

    public function mpesaStkPush(Request $request): JsonResponse
    {
        $request->validate([
            'phone_number' => 'required|string|regex:/^\+254[0-9]{9}$/',
            'amount' => 'required|numeric|min:1',
            'order_id' => 'required|exists:orders,id',
        ]);

        // This is a placeholder for M-Pesa STK Push integration
        // In a real implementation, you would:
        // 1. Generate access token from M-Pesa API
        // 2. Send STK Push request
        // 3. Store transaction details
        // 4. Return transaction ID for polling

        return response()->json([
            'message' => 'STK Push initiated successfully',
            'transaction_id' => 'STK' . time(),
            'checkout_request_id' => 'ws_CO_' . time(),
        ]);
    }

    public function mpesaCallback(Request $request): JsonResponse
    {
        // This is a placeholder for M-Pesa callback handling
        // In a real implementation, you would:
        // 1. Validate the callback signature
        // 2. Extract transaction details
        // 3. Update payment status
        // 4. Send confirmation response

        \Log::info('M-Pesa Callback received', $request->all());

        return response()->json(['ResultCode' => 0, 'ResultDesc' => 'Success']);
    }

    public function mpesaWebhook(Request $request): JsonResponse
    {
        // This is a placeholder for M-Pesa webhook handling
        // Similar to callback but for different M-Pesa integration methods

        \Log::info('M-Pesa Webhook received', $request->all());

        return response()->json(['status' => 'success']);
    }
}