<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Payment;
use App\Models\Order;
use App\Services\MpesaService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class PaymentController extends Controller
{
    protected MpesaService $mpesa;

    public function __construct(MpesaService $mpesa)
    {
        $this->mpesa = $mpesa;
    }

    // Customer: initiate STK push for an order
    public function initiatePayment(Request $request)
    {
        $request->validate([
            'order_id' => 'required|exists:orders,id',
            'phone' => 'required|string',
        ]);

        $order = Order::findOrFail($request->order_id);

        if ($order->customer_id !== $request->user()->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        if (!$order->total_amount || $order->total_amount <= 0) {
            return response()->json(['message' => 'Order amount not yet determined. Weight must be confirmed first.'], 422);
        }

        // Check if there is already a completed payment
        $existingPayment = Payment::where('order_id', $order->id)->where('status', 'completed')->first();
        if ($existingPayment) {
            return response()->json(['message' => 'Order already paid'], 422);
        }

        $accountRef = 'DC-' . $order->id;
        $description = 'Dry cleaning payment for order #' . $order->id;

        $result = $this->mpesa->stkPush($request->phone, $order->total_amount, $accountRef, $description);

        if ($result['success']) {
            $payment = Payment::create([
                'order_id' => $order->id,
                'user_id' => $request->user()->id,
                'amount' => $order->total_amount,
                'phone' => $request->phone,
                'merchant_request_id' => $result['merchant_request_id'],
                'checkout_request_id' => $result['checkout_request_id'],
                'status' => 'pending',
            ]);

            return response()->json([
                'message' => 'STK push sent to your phone. Please enter your M-Pesa PIN.',
                'payment' => $payment,
                'checkout_request_id' => $result['checkout_request_id'],
            ]);
        }

        return response()->json([
            'message' => 'Payment initiation failed',
            'error' => $result['message'],
        ], 400);
    }

    // M-Pesa callback
    public function mpesaCallback(Request $request)
    {
        Log::info('M-Pesa Callback', ['data' => $request->all()]);

        $callbackData = $request->input('Body.stkCallback', $request->all());

        $merchantRequestId = $callbackData['MerchantRequestID'] ?? null;
        $checkoutRequestId = $callbackData['CheckoutRequestID'] ?? null;
        $resultCode = $callbackData['ResultCode'] ?? null;
        $resultDesc = $callbackData['ResultDesc'] ?? null;

        if (!$checkoutRequestId) {
            return response()->json(['message' => 'Invalid callback data']);
        }

        $payment = Payment::where('checkout_request_id', $checkoutRequestId)->first();

        if (!$payment) {
            Log::error('Payment not found for callback', ['checkout_request_id' => $checkoutRequestId]);
            return response()->json(['message' => 'Payment not found']);
        }

        if ($resultCode == 0) {
            // Success
            $metadata = $callbackData['CallbackMetadata']['Item'] ?? [];
            $mpesaReceipt = '';
            $transactionDate = null;

            foreach ($metadata as $item) {
                if ($item['Name'] === 'MpesaReceiptNumber') {
                    $mpesaReceipt = $item['Value'];
                }
                if ($item['Name'] === 'TransactionDate') {
                    $transactionDate = $item['Value'];
                }
            }

            $payment->update([
                'status' => 'completed',
                'mpesa_receipt' => $mpesaReceipt,
                'result_desc' => $resultDesc,
                'callback_data' => $callbackData,
                'transaction_date' => $transactionDate ? \Carbon\Carbon::createFromFormat('YmdHis', $transactionDate) : now(),
            ]);

            // Move order to next status if appropriate
            $order = $payment->order;
            if (in_array($order->status, ['delivered', 'washed'])) {
                $order->update([
                    'status' => 'completed',
                    'completed_at' => now(),
                ]);
            }
        } else {
            $payment->update([
                'status' => 'failed',
                'result_desc' => $resultDesc,
                'callback_data' => $callbackData,
            ]);
        }

        return response()->json(['message' => 'Callback processed']);
    }

    // Check payment status
    public function checkStatus(Request $request, Payment $payment)
    {
        if ($payment->user_id !== $request->user()->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $liveResult = null;

        // Also query M-Pesa for live status
        if ($payment->status === 'pending' && $payment->checkout_request_id) {
            $result = $this->mpesa->queryTransactionStatus($payment->checkout_request_id);
            if ($result['success']) {
                $data = $result['data'];
                $liveResult = $data;
                if (isset($data['ResultCode'])) {
                    if ($data['ResultCode'] == 0) {
                        $payment->update([
                            'status' => 'completed',
                            'result_desc' => $data['ResultDesc'] ?? 'Payment received',
                        ]);
                    } elseif ((string) $data['ResultCode'] === '4999') {
                        $payment->update([
                            'status' => 'pending',
                            'result_desc' => $data['ResultDesc'] ?? 'Payment sent, waiting for customer action',
                        ]);
                    } else {
                        $payment->update([
                            'status' => 'failed',
                            'result_desc' => $data['ResultDesc'] ?? 'Payment rejected',
                        ]);
                    }
                }
            }
        }

        $payment->refresh();

        return response()->json([
            ...$payment->toArray(),
            'live_result' => $liveResult,
        ]);
    }

    // Customer: payment history
    public function myPayments(Request $request)
    {
        $payments = Payment::with('order.dryCleaner:id,name')
            ->where('user_id', $request->user()->id)
            ->latest()
            ->paginate(20);

        return response()->json($payments);
    }

    // Owner: payment history for their DC
    public function dcPayments(Request $request, $dryCleanerId)
    {
        $payments = Payment::whereHas('order', function ($q) use ($dryCleanerId, $request) {
            $q->where('dry_cleaner_id', $dryCleanerId)
                ->whereHas('dryCleaner', function ($q2) use ($request) {
                    $q2->where('owner_id', $request->user()->id);
                });
        })
            ->with(['order:id,status,weight_kg,total_amount,customer_id', 'order.customer:id,name,phone'])
            ->latest()
            ->paginate(20);

        return response()->json($payments);
    }

    // Get M-Pesa account balance
    public function balance(Request $request)
    {
        if ($request->user()->role !== 'owner') {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $result = $this->mpesa->getAccountBalance();
        return response()->json($result);
    }
}
