<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Purchase;
use App\Models\Supplier;
use App\Models\SupplierPayment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

class SupplierPaymentController extends Controller
{
    /**
     * List payments for a supplier, or all payments if no supplier scoped.
     */
    public function index(Request $request)
    {
        $this->authorize('view-purchases');

        $query = SupplierPayment::with(['supplier', 'purchase', 'user'])
            ->latest('payment_date');

        if ($request->filled('supplier_id')) {
            $query->where('supplier_id', $request->input('supplier_id'));
        }

        if ($request->filled('purchase_id')) {
            $query->where('purchase_id', $request->input('purchase_id'));
        }

        if ($request->filled('payment_method')) {
            $query->where('payment_method', $request->input('payment_method'));
        }

        if ($request->filled('date_from')) {
            $query->whereDate('payment_date', '>=', $request->input('date_from'));
        }

        if ($request->filled('date_to')) {
            $query->whereDate('payment_date', '<=', $request->input('date_to'));
        }

        $payments = $query->paginate(min((int) $request->input('per_page', 15), 100));

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

    /**
     * Record a payment against a supplier (optionally allocated to a specific purchase).
     */
    public function store(Request $request)
    {
        $this->authorize('create-purchases');

        $orgId = app('current_organization_id');

        $validated = $request->validate([
            'supplier_id'    => ['required', Rule::exists('suppliers', 'id')->where('organization_id', $orgId)],
            'purchase_id'    => ['nullable', Rule::exists('purchases', 'id')->where('organization_id', $orgId)],
            'amount'         => 'required|numeric|min:0.01',
            'payment_date'   => 'required|date',
            'payment_method' => 'required|in:cash,bank_transfer,cheque,card,other',
            'reference'      => 'nullable|string|max:255',
            'notes'          => 'nullable|string',
        ]);

        // If tied to a specific purchase, validate supplier match and amount
        if (!empty($validated['purchase_id'])) {
            $purchase = Purchase::where('id', $validated['purchase_id'])
                ->where('organization_id', $orgId)
                ->firstOrFail();

            if ((int) $purchase->supplier_id !== (int) $validated['supplier_id']) {
                return response()->json([
                    'message' => 'Purchase does not belong to the specified supplier.',
                ], 422);
            }

            if ($validated['amount'] > (float) $purchase->amount_due) {
                return response()->json([
                    'message' => 'Payment amount exceeds the amount due for this purchase.',
                    'amount_due' => $purchase->amount_due,
                ], 422);
            }
        }

        $payment = DB::transaction(function () use ($validated, $request, $orgId) {
            $payment = SupplierPayment::create([
                'payment_number' => $this->generatePaymentNumber(),
                'supplier_id'    => $validated['supplier_id'],
                'purchase_id'    => $validated['purchase_id'] ?? null,
                'user_id'        => $request->user()->id,
                'organization_id'=> $orgId,
                'amount'         => $validated['amount'],
                'payment_date'   => $validated['payment_date'],
                'payment_method' => $validated['payment_method'],
                'reference'      => $validated['reference'] ?? null,
                'notes'          => $validated['notes'] ?? null,
            ]);

            // Update the linked purchase's payment balance
            if ($payment->purchase_id) {
                $this->reconcilePurchasePayment($payment->purchase);
            }

            return $payment->load(['supplier', 'purchase', 'user']);
        });

        return response()->json(['data' => $payment], 201);
    }

    /**
     * Show a single payment.
     */
    public function show(SupplierPayment $supplierPayment)
    {
        $this->authorize('view-purchases');

        return response()->json([
            'data' => $supplierPayment->load(['supplier', 'purchase', 'user']),
        ]);
    }

    /**
     * Void / soft-delete a payment and reverse its effect on the purchase.
     */
    public function destroy(SupplierPayment $supplierPayment)
    {
        $this->authorize('edit-purchases');

        DB::transaction(function () use ($supplierPayment) {
            $purchaseId = $supplierPayment->purchase_id;
            $supplierPayment->delete();

            if ($purchaseId) {
                $purchase = Purchase::find($purchaseId);
                if ($purchase) {
                    $this->reconcilePurchasePayment($purchase);
                }
            }
        });

        return response()->json(['message' => 'Payment voided successfully.']);
    }

    // -------------------------------------------------------------------------
    // Helpers
    // -------------------------------------------------------------------------

    /**
     * Recalculate amount_paid, amount_due, and payment_status for a purchase
     * based on its active (non-deleted) supplier payments.
     */
    private function reconcilePurchasePayment(Purchase $purchase): void
    {
        $totalPaid = SupplierPayment::where('purchase_id', $purchase->id)->sum('amount');

        $amountDue  = max(0, (float) $purchase->total - (float) $totalPaid);

        if ($totalPaid <= 0) {
            $status = 'unpaid';
        } elseif ($amountDue > 0) {
            $status = 'partial';
        } else {
            $status = 'paid';
        }

        $purchase->update([
            'amount_paid'    => $totalPaid,
            'amount_due'     => $amountDue,
            'payment_status' => $status,
        ]);
    }

    private function generatePaymentNumber(): string
    {
        $prefix = 'SPY';
        $date   = now()->format('Ymd');
        $count  = SupplierPayment::whereDate('created_at', today())->count() + 1;
        $seq    = str_pad($count, 4, '0', STR_PAD_LEFT);

        return "{$prefix}{$date}{$seq}";
    }
}
