<?php

namespace App\Http\Controllers;

use App\Models\Payment;
use App\Models\PaymentMethod;
use App\Models\PaymentStatus;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class PaymentController extends Controller
{
    public function index(Request $request)
    {
        $query = Payment::with([
            'order',
            'customer',
            'method',
            'status',
            'receiver'
        ]);

        // Search
        if ($request->filled('search')) {

            $search = $request->search;

            $query->where(function ($q) use ($search) {

                $q->whereHas('customer', function ($customerQuery) use ($search) {
                    $customerQuery->where('customer_name', 'like', '%' . $search . '%');
                })

                ->orWhereHas('order', function ($orderQuery) use ($search) {
                    $orderQuery->where('serial_number', 'like', '%' . $search . '%');
                });

            });
        }

        // Payment Status Filter
        if ($request->filled('status_id')) {
            $query->where('status_id', $request->status_id);
        }

        // Payment Method Filter
        if ($request->filled('method_id')) {
            $query->where('payment_method', $request->method_id);
        }

        // Date Filter
        if ($request->filled('payment_date')) {
            $query->whereDate('payment_date', $request->payment_date);
        }

        $payments = $query
            ->orderBy('payment_id', 'desc')
            ->paginate(10)
            ->withQueryString();

        // Summary Cards
        $totalPayments = Payment::count();

        $paidStatus = PaymentStatus::whereRaw(
            'LOWER(status_name) = ?',
            ['paid']
        )->first();

        $pendingStatus = PaymentStatus::whereRaw(
            'LOWER(status_name) = ?',
            ['pending']
        )->first();

        $paidInvoices = $paidStatus
            ? Payment::where('status_id', $paidStatus->status_id)->count()
            : 0;

        $pendingInvoices = $pendingStatus
            ? Payment::where('status_id', $pendingStatus->status_id)->count()
            : 0;

        $totalPayment = Payment::sum('amount_paid');

        // Dropdown data
        $paymentMethods = PaymentMethod::orderBy('method_type')->get();

        $paymentStatuses = PaymentStatus::orderBy('status_name')->get();

       return view('payment.payment', compact(
      'payments',
      'totalPayments',
       'paidInvoices',
       'pendingInvoices',
      'totalPayment',
      'paymentMethods',
      'paymentStatuses'
));
    }
    /*
|--------------------------------------------------------------------------
| Add Payment Page
|--------------------------------------------------------------------------
*/

public function create()
{
    $orders = Order::with([
        'customer',
        'invoice'
    ])
    ->withSum('payments', 'amount_paid')
    ->orderBy('order_id', 'desc')
    ->get();

    $paymentMethods = PaymentMethod::orderBy('method_type')->get();

    return view('payment.add', compact(
        'orders',
        'paymentMethods'
    ));
}
/*|--------------------------------------------------------------------------
| Payment Summary
|--------------------------------------------------------------------------
*/

public function summary($orderId)
{
    $order = Order::findOrFail($orderId);

    $alreadyPaid = Payment::where(
        'order_id',
        $order->order_id
    )->sum('amount_paid');

    $totalAmount = (float) ($order->total_amount ?? 0);

    $remainingAmount = $totalAmount - (float) $alreadyPaid;

    return response()->json([
        'invoice_total' => $totalAmount,
        'already_paid' => (float) $alreadyPaid,
        'remaining_amount' => max($remainingAmount, 0),
    ]);
}

/*
|--------------------------------------------------------------------------
| Store Payment
|--------------------------------------------------------------------------
*/

public function store(Request $request)
{
    $validated = $request->validate([

        'order_id' => [
            'required',
            'integer',
            'exists:orders,order_id'
        ],

        'payment_method' => [
            'required',
            'integer',
            'exists:payment_method,method_id'
        ],

        'payment_date' => [
            'required',
            'date'
        ],

        'amount_paid' => [
            'required',
            'numeric',
            'min:0.01'
        ],

    ]);

    try {

        DB::beginTransaction();

        $user = Auth::user();

        if (!$user) {
            abort(403);
        }

        /*
        |--------------------------------------------------------------------------
        | Find Order
        |--------------------------------------------------------------------------
        */

        $order = Order::with('customer')
            ->findOrFail($validated['order_id']);


        /*
        |--------------------------------------------------------------------------
        | Calculate Already Paid Amount
        |--------------------------------------------------------------------------
        */

        $alreadyPaid = Payment::where(
            'order_id',
            $order->order_id
        )->sum('amount_paid');


        /*
        |--------------------------------------------------------------------------
        | Remaining Before Payment
        |--------------------------------------------------------------------------
        */

        $remainingBeforePayment =
            (float) $order->total_amount
            - (float) $alreadyPaid;


        /*
        |--------------------------------------------------------------------------
        | Validate Payment Amount
        |--------------------------------------------------------------------------
        */

        if ($validated['amount_paid'] > $remainingBeforePayment) {

            throw new \Exception(
                'Payment amount cannot be greater than remaining balance. Remaining balance: Rs. ' .
                number_format($remainingBeforePayment, 2)
            );
        }


        /*
        |--------------------------------------------------------------------------
        | Calculate Remaining Amount
        |--------------------------------------------------------------------------
        */

        $remainingAmount =
            $remainingBeforePayment
            - (float) $validated['amount_paid'];


        /*
        |--------------------------------------------------------------------------
        | Determine Payment Status
        |--------------------------------------------------------------------------
        */

        if ($remainingAmount <= 0) {

            $statusName = 'paid';

        } elseif ($alreadyPaid > 0 || $validated['amount_paid'] > 0) {

            $statusName = 'partial';

        } else {

            $statusName = 'pending';
        }


        $status = PaymentStatus::whereRaw(
            'LOWER(status_name) = ?',
            [$statusName]
        )->first();


        if (!$status) {

            throw new \Exception(
                ucfirst($statusName) .
                ' payment status does not exist.'
            );
        }


        /*
        |--------------------------------------------------------------------------
        | Create Payment
        |--------------------------------------------------------------------------
        */

        $payment = Payment::create([

            'order_id' =>
                $order->order_id,

            'customer_id' =>
                $order->customer_id,

            'payment_method' =>
                $validated['payment_method'],

            'payment_date' =>
                $validated['payment_date'],

            'amount_paid' =>
                $validated['amount_paid'],

            'remaining_amount' =>
                $remainingAmount,

            'received_by' =>
                $user->user_id,

            'status_id' =>
                $status->status_id,

        ]);


        DB::commit();


        return redirect()
            ->route(
                'payments.index'
            )
            ->with(
                'success',
                'Payment added successfully.'
            );


    } catch (\Throwable $e) {

        DB::rollBack();

        return back()
            ->withInput()
            ->with(
                'error',
                $e->getMessage()
            );
    }
}
public function show(Payment $payment)
{
    $payment->load([
        'order',
        'customer',
        'method',
        'status',
        'receiver'
    ]);

    return view('payment.show', compact('payment'));
}
public function edit(Payment $payment)
{
    $payment->load([
        'order',
        'customer',
        'method',
        'status',
        'receiver'
    ]);

    $orders = Order::with([
        'customer',
        'invoice'
    ])
    ->orderBy('order_id', 'desc')
    ->get();

    $paymentMethods = PaymentMethod::orderBy('method_type')->get();

    return view('payment.edit', compact(
        'payment',
        'orders',
        'paymentMethods'
    ));
}
public function update(Request $request, Payment $payment)
{
    $validated = $request->validate([

        'order_id' => [
            'required',
            'integer',
            'exists:orders,order_id'
        ],

        'payment_method' => [
            'required',
            'integer',
            'exists:payment_method,method_id'
        ],

        'payment_date' => [
            'required',
            'date'
        ],

        'amount_paid' => [
            'required',
            'numeric',
            'min:0.01'
        ],

    ]);

    try {

        DB::beginTransaction();

        $order = Order::findOrFail($validated['order_id']);

        /*
        |--------------------------------------------------------------------------
        | Existing payments excluding current payment
        |--------------------------------------------------------------------------
        */

        $alreadyPaid = Payment::where('order_id', $order->order_id)
            ->where('payment_id', '!=', $payment->payment_id)
            ->sum('amount_paid');

        $remainingBeforePayment =
            (float) $order->total_amount - (float) $alreadyPaid;

        if ($validated['amount_paid'] > $remainingBeforePayment) {

            throw new \Exception(
                'Payment amount cannot be greater than remaining balance. Remaining balance: Rs. ' .
                number_format($remainingBeforePayment, 2)
            );
        }

        /*
        |--------------------------------------------------------------------------
        | Calculate remaining amount
        |--------------------------------------------------------------------------
        */

        $remainingAmount =
            $remainingBeforePayment -
            (float) $validated['amount_paid'];

        /*
        |--------------------------------------------------------------------------
        | Determine status
        |--------------------------------------------------------------------------
        */

        if ($remainingAmount <= 0) {

            $statusName = 'paid';

        } elseif (
            $alreadyPaid > 0 ||
            $validated['amount_paid'] > 0
        ) {

            $statusName = 'partial';

        } else {

            $statusName = 'pending';
        }

        $status = PaymentStatus::whereRaw(
            'LOWER(status_name) = ?',
            [$statusName]
        )->first();

        if (!$status) {

            throw new \Exception(
                ucfirst($statusName) .
                ' payment status does not exist.'
            );
        }

        /*
        |--------------------------------------------------------------------------
        | Update payment
        |--------------------------------------------------------------------------
        */

        $payment->update([

            'order_id' =>
                $order->order_id,

            'customer_id' =>
                $order->customer_id,

            'payment_method' =>
                $validated['payment_method'],

            'payment_date' =>
                $validated['payment_date'],

            'amount_paid' =>
                $validated['amount_paid'],

            'remaining_amount' =>
                $remainingAmount,

            'status_id' =>
                $status->status_id,

        ]);

        DB::commit();

        return redirect()
            ->route('payments.index')
            ->with(
                'success',
                'Payment updated successfully.'
            );

    } catch (\Throwable $e) {

        DB::rollBack();

        return back()
            ->withInput()
            ->with(
                'error',
                $e->getMessage()
            );
    }
}
public function destroy(Payment $payment)
{
    try {

        $payment->delete();

        return redirect()
            ->route('payments.index')
            ->with(
                'success',
                'Payment deleted successfully.'
            );

    } catch (\Throwable $e) {

        return back()
            ->with(
                'error',
                'Unable to delete payment: ' . $e->getMessage()
            );
    }
}
}