<?php

namespace App\Http\Controllers;

use App\Models\Payment;
use App\Models\Order;
use App\Models\AuditLog;
use App\Models\SystemSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\DB;

class PaymentController extends Controller
{
    /**
     * Initiate a payment
     */
    public function initiate(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'order_id' => 'required|exists:orders,id',
            'payment_method' => 'required|in:mpesa,pesapal,paypal,cash',
            'customer_phone' => 'required_if:payment_method,mpesa|string|max:20',
            'customer_email' => 'required_if:payment_method,pesapal,paypal|email|max:255',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            $user = auth()->user();
            $order = Order::find($request->order_id);

            // Check if user owns the order
            if ($order->customer_id != $user->id) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized to initiate payment for this order'
                ], 403);
            }

            // Check if order is already paid
            if ($order->payment_status === 'paid') {
                return response()->json([
                    'success' => false,
                    'message' => 'Order is already paid'
                ], 422);
            }

            // Create payment record
            $payment = Payment::create([
                'order_id' => $order->id,
                'payment_method' => $request->payment_method,
                'amount' => $order->final_amount,
                'currency' => 'KES',
                'status' => 'pending',
                'customer_phone' => $request->customer_phone,
                'customer_email' => $request->customer_email,
                'description' => "Payment for order #{$order->order_number}",
            ]);

            // Process payment based on method
            $paymentResult = $this->processPayment($payment, $request);

            if (!$paymentResult['success']) {
                $payment->update([
                    'status' => 'failed',
                    'gateway_response' => $paymentResult
                ]);

                return response()->json([
                    'success' => false,
                    'message' => 'Payment initiation failed',
                    'error' => $paymentResult['message']
                ], 422);
            }

            // Update payment with gateway response
            $payment->update([
                'transaction_id' => $paymentResult['transaction_id'] ?? null,
                'gateway_response' => $paymentResult
            ]);

            // Log the payment initiation
            AuditLog::logCreate($user, $payment, $request);

            return response()->json([
                'success' => true,
                'message' => 'Payment initiated successfully',
                'data' => [
                    'payment' => $payment->load(['order']),
                    'gateway_response' => $paymentResult
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to initiate payment',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Confirm a payment
     */
    public function confirm(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'payment_id' => 'required|exists:payments,id',
            'transaction_id' => 'required|string',
            'status' => 'required|in:successful,failed',
            'gateway_response' => 'nullable|array',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            DB::beginTransaction();

            $user = auth()->user();
            $payment = Payment::with(['order'])->find($request->payment_id);

            // Check if user owns the payment
            if ($payment->order->customer_id != $user->id && !$user->isAdmin()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized to confirm this payment'
                ], 403);
            }

            $oldStatus = $payment->status;
            $payment->update([
                'status' => $request->status,
                'transaction_id' => $request->transaction_id,
                'gateway_response' => array_merge(
                    $payment->gateway_response ?? [],
                    $request->gateway_response ?? [],
                    ['confirmation' => $request->all()]
                )
            ]);

            // Update order payment status if payment is successful
            if ($request->status === 'successful') {
                $payment->order->update([
                    'payment_status' => 'paid'
                ]);

                // Send payment confirmation SMS
                $this->sendPaymentConfirmationSms($payment);
            }

            // Log the payment confirmation
            AuditLog::log($user, 'payment_confirmation', $payment, 
                ['status' => $oldStatus], 
                ['status' => $request->status], 
                $request
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Payment confirmed successfully',
                'data' => [
                    'payment' => $payment->load(['order'])
                ]
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Failed to confirm payment',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get payment history for authenticated user
     */
    public function paymentHistory(Request $request)
    {
        try {
            $user = auth()->user();
            
            $query = Payment::with(['order'])
                ->whereHas('order', function($q) use ($user) {
                    $q->where('customer_id', $user->id);
                });

            // Filter by status
            if ($request->has('status') && $request->status) {
                $query->where('status', $request->status);
            }

            // Filter by payment method
            if ($request->has('payment_method') && $request->payment_method) {
                $query->where('payment_method', $request->payment_method);
            }

            // Filter by date range
            if ($request->has('start_date') && $request->has('end_date')) {
                $query->byDateRange($request->start_date, $request->end_date);
            }

            // Sort by creation date (most recent first)
            $query->orderBy('created_at', 'desc');

            // Pagination
            $perPage = $request->get('per_page', 10);
            $payments = $query->paginate($perPage);

            return response()->json([
                'success' => true,
                'message' => 'Payment history retrieved successfully',
                'data' => [
                    'payments' => $payments->items(),
                    'pagination' => [
                        'current_page' => $payments->currentPage(),
                        'per_page' => $payments->perPage(),
                        'total' => $payments->total(),
                        'last_page' => $payments->lastPage(),
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve payment history',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display the specified payment
     */
    public function show($id)
    {
        try {
            $user = auth()->user();
            
            $payment = Payment::with(['order.items.product'])->find($id);

            if (!$payment) {
                return response()->json([
                    'success' => false,
                    'message' => 'Payment not found'
                ], 404);
            }

            // Check if user owns the payment or is admin
            if ($payment->order->customer_id != $user->id && !$user->isAdmin()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized to view this payment'
                ], 403);
            }

            return response()->json([
                'success' => true,
                'message' => 'Payment retrieved successfully',
                'data' => [
                    'payment' => $payment
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve payment',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display a listing of all payments (admin only)
     */
    public function adminIndex(Request $request)
    {
        try {
            $query = Payment::with(['order.customer']);

            // Filter by status
            if ($request->has('status') && $request->status) {
                $query->where('status', $request->status);
            }

            // Filter by payment method
            if ($request->has('payment_method') && $request->payment_method) {
                $query->where('payment_method', $request->payment_method);
            }

            // Filter by date range
            if ($request->has('start_date') && $request->has('end_date')) {
                $query->byDateRange($request->start_date, $request->end_date);
            }

            // Search by transaction ID or customer details
            if ($request->has('search') && $request->search) {
                $query->where(function($q) use ($request) {
                    $q->where('transaction_id', 'like', '%' . $request->search . '%')
                      ->orWhere('customer_phone', 'like', '%' . $request->search . '%')
                      ->orWhere('customer_email', 'like', '%' . $request->search . '%')
                      ->orWhereHas('order', function($q2) use ($request) {
                          $q2->where('order_number', 'like', '%' . $request->search . '%')
                             ->orWhere('customer_name', 'like', '%' . $request->search . '%');
                      });
                });
            }

            // Sort options
            $sortBy = $request->get('sort_by', 'created_at');
            $sortOrder = $request->get('sort_order', 'desc');
            $query->orderBy($sortBy, $sortOrder);

            // Pagination
            $perPage = $request->get('per_page', 15);
            $payments = $query->paginate($perPage);

            return response()->json([
                'success' => true,
                'message' => 'Payments retrieved successfully',
                'data' => [
                    'payments' => $payments->items(),
                    'pagination' => [
                        'current_page' => $payments->currentPage(),
                        'per_page' => $payments->perPage(),
                        'total' => $payments->total(),
                        'last_page' => $payments->lastPage(),
                    ]
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve payments',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Process refund for a payment (admin only)
     */
    public function refund(Request $request, $id)
    {
        $validator = Validator::make($request->all(), [
            'refund_amount' => 'required|numeric|min:0.01',
            'reason' => 'required|string|max:500',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors()
            ], 422);
        }

        try {
            DB::beginTransaction();

            $user = auth()->user();
            $payment = Payment::with(['order'])->find($id);

            if (!$payment) {
                return response()->json([
                    'success' => false,
                    'message' => 'Payment not found'
                ], 404);
            }

            // Check if payment is successful
            if ($payment->status !== 'successful') {
                return response()->json([
                    'success' => false,
                    'message' => 'Can only refund successful payments'
                ], 422);
            }

            // Check refund amount
            if ($request->refund_amount > $payment->amount) {
                return response()->json([
                    'success' => false,
                    'message' => 'Refund amount cannot exceed original payment amount'
                ], 422);
            }

            // Process refund through payment gateway
            $refundResult = $this->processRefund($payment, $request->refund_amount, $request->reason);

            if (!$refundResult['success']) {
                return response()->json([
                    'success' => false,
                    'message' => 'Refund processing failed',
                    'error' => $refundResult['message']
                ], 422);
            }

            // Create refund record (as a new payment with negative amount)
            $refundPayment = Payment::create([
                'order_id' => $payment->order_id,
                'payment_method' => $payment->payment_method,
                'transaction_id' => $refundResult['refund_id'] ?? null,
                'amount' => -$request->refund_amount,
                'currency' => $payment->currency,
                'status' => 'successful',
                'gateway_response' => $refundResult,
                'customer_phone' => $payment->customer_phone,
                'customer_email' => $payment->customer_email,
                'description' => "Refund: {$request->reason}",
                'metadata' => [
                    'original_payment_id' => $payment->id,
                    'refund_reason' => $request->reason,
                ]
            ]);

            // Update order payment status if full refund
            if ($request->refund_amount == $payment->amount) {
                $payment->order->update([
                    'payment_status' => 'refunded'
                ]);
            }

            // Log the refund
            AuditLog::log($user, 'refund', $refundPayment, null, [
                'original_payment_id' => $payment->id,
                'refund_amount' => $request->refund_amount,
                'reason' => $request->reason
            ], $request);

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Refund processed successfully',
                'data' => [
                    'refund' => $refundPayment,
                    'gateway_response' => $refundResult
                ]
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Failed to process refund',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Generate payment report (admin only)
     */
    public function paymentReport(Request $request)
    {
        try {
            $startDate = $request->get('start_date', now()->subMonth()->format('Y-m-d'));
            $endDate = $request->get('end_date', now()->format('Y-m-d'));

            $report = DB::table('payments')
                ->select(
                    DB::raw('COUNT(*) as total_payments'),
                    DB::raw('SUM(amount) as total_amount'),
                    DB::raw('AVG(amount) as average_payment'),
                    DB::raw('COUNT(CASE WHEN status = "successful" THEN 1 END) as successful_payments'),
                    DB::raw('SUM(CASE WHEN status = "successful" THEN amount ELSE 0 END) as successful_amount'),
                    DB::raw('COUNT(CASE WHEN status = "failed" THEN 1 END) as failed_payments'),
                    DB::raw('COUNT(CASE WHEN status = "pending" THEN 1 END) as pending_payments')
                )
                ->whereBetween('created_at', [$startDate, $endDate])
                ->where('amount', '>', 0) // Exclude refunds
                ->first();

            // Payment method breakdown
            $methodBreakdown = DB::table('payments')
                ->select(
                    'payment_method',
                    DB::raw('COUNT(*) as payment_count'),
                    DB::raw('SUM(amount) as total_amount')
                )
                ->whereBetween('created_at', [$startDate, $endDate])
                ->where('amount', '>', 0)
                ->where('status', 'successful')
                ->groupBy('payment_method')
                ->get();

            // Daily payment trend
            $dailyTrend = DB::table('payments')
                ->select(
                    DB::raw('DATE(created_at) as date'),
                    DB::raw('COUNT(*) as payment_count'),
                    DB::raw('SUM(amount) as daily_amount')
                )
                ->whereBetween('created_at', [$startDate, $endDate])
                ->where('amount', '>', 0)
                ->where('status', 'successful')
                ->groupBy('date')
                ->orderBy('date')
                ->get();

            return response()->json([
                'success' => true,
                'message' => 'Payment report generated successfully',
                'data' => [
                    'report_period' => [
                        'start_date' => $startDate,
                        'end_date' => $endDate,
                    ],
                    'summary' => $report,
                    'method_breakdown' => $methodBreakdown,
                    'daily_trend' => $dailyTrend,
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to generate payment report',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Process payment through gateway
     */
    private function processPayment(Payment $payment, Request $request)
    {
        $method = $payment->payment_method;
        
        switch ($method) {
            case 'mpesa':
                return $this->processMpesaPayment($payment, $request);
            case 'pesapal':
                return $this->processPesapalPayment($payment, $request);
            case 'paypal':
                return $this->processPaypalPayment($payment, $request);
            case 'cash':
                return [
                    'success' => true,
                    'message' => 'Cash payment initiated',
                    'transaction_id' => 'CASH-' . time()
                ];
            default:
                return [
                    'success' => false,
                    'message' => 'Unsupported payment method'
                ];
        }
    }

    /**
     * Process M-Pesa payment
     */
    private function processMpesaPayment(Payment $payment, Request $request)
    {
        // This is a simplified implementation
        // In production, you would integrate with actual M-Pesa API
        
        $phone = $request->customer_phone;
        $amount = $payment->amount;
        
        // Simulate M-Pesa STK push
        return [
            'success' => true,
            'message' => 'M-Pesa payment initiated successfully',
            'transaction_id' => 'MPESA' . time(),
            'checkout_request_id' => 'ws_CO_' . time(),
            'customer_message' => 'Please enter your M-Pesa PIN to complete payment',
        ];
    }

    /**
     * Process Pesapal payment
     */
    private function processPesapalPayment(Payment $payment, Request $request)
    {
        // Simplified Pesapal integration
        return [
            'success' => true,
            'message' => 'Pesapal payment initiated successfully',
            'transaction_id' => 'PESAPAL' . time(),
            'redirect_url' => 'https://pesapal.com/payment/' . time(),
        ];
    }


    /**
     * Process PayPal payment
     */
    private function processPaypalPayment(Payment $payment, Request $request)
    {
        // Simplified PayPal integration
        return [
            'success' => true,
            'message' => 'PayPal payment initiated successfully',
            'transaction_id' => 'PAYPAL' . time(),
            'approval_url' => 'https://paypal.com/checkout/' . time(),
        ];
    }

    /**
     * Process refund through gateway
     */
    private function processRefund(Payment $payment, $amount, $reason)
    {
        // Simplified refund processing
        return [
            'success' => true,
            'message' => 'Refund processed successfully',
            'refund_id' => 'REFUND' . time(),
            'refund_amount' => $amount,
            'reason' => $reason,
        ];
    }

    /**
     * Send payment confirmation SMS
     */
    private function sendPaymentConfirmationSms(Payment $payment)
    {
        // This would integrate with your SMS service
        $message = "Payment of KES {$payment->amount} for order #{$payment->order->order_number} has been confirmed. Thank you for your business!";
        
        // In production, you would call your SMS service here
        // SmsService::send($payment->customer_phone, $message);
        
        return true;
    }
}