<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\Rental\StoreRentalRequest;
use App\Http\Requests\Rental\RenewRentalRequest;
use App\Http\Resources\RentalResource;
use App\Models\Locker;
use App\Models\LostKeyIncident;
use App\Models\Rental;
use App\Models\RentalRenewal;
use App\Services\RentalService;
use App\Services\InvoiceService;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;

class RentalController extends Controller
{
    public function __construct(
        protected RentalService  $rentalService,
        protected InvoiceService $invoiceService,
    ) {}

    /**
     * GET /api/rentals
     */
    public function index(Request $request)
    {
        $query = Rental::with(['client', 'locker.category', 'locker.zone', 'assignedBy']);

        if ($status = $request->get('status')) {
            $query->where('status', $status);
        }
        if ($clientId = $request->get('client_id')) {
            $query->where('client_id', $clientId);
        }
        if ($search = $request->get('search')) {
            $query->where(function ($q) use ($search) {
                $q->where('rental_number', 'like', "%{$search}%")
                  ->orWhereHas('client', fn($c) => $c->search($search));
            });
        }

        return RentalResource::collection(
            $query->latest()->paginate($request->get('per_page', 20))
        );
    }

    /**
     * POST /api/rentals
     */
    public function store(StoreRentalRequest $request)
    {
        $rental = $this->rentalService->createRental($request->validated(), auth()->user());
        return new RentalResource($rental->load('client', 'locker.category', 'invoices'));
    }

    /**
     * GET /api/rentals/expiring
     */
    public function expiring(Request $request)
    {
        $days    = $request->get('days', 7);
        $rentals = Rental::expiring($days)->with(['client', 'locker'])->latest('end_date')->get();
        return RentalResource::collection($rentals);
    }

    /**
     * GET /api/rentals/overdue
     */
    public function overdue()
    {
        $rentals = Rental::overdue()->with(['client', 'locker'])->oldest('end_date')->get();
        return RentalResource::collection($rentals);
    }

    /**
     * GET /api/rentals/{rental}
     */
    public function show(Rental $rental)
    {
        $rental->load([
            'client', 'locker.category', 'locker.zone',
            'assignedBy', 'keyIssuedBy', 'keyReturnedBy',
            'payments.paymentMethod', 'payments.collectedBy',
            'invoices', 'renewals.renewedBy',
            'lostKeyIncidents.reportedBy',
            'notificationLogs',
        ]);
        return new RentalResource($rental);
    }

    /**
     * PUT /api/rentals/{rental}
     */
    public function update(Request $request, Rental $rental)
    {
        $request->validate(['notes' => 'nullable|string']);
        $rental->update($request->only('notes'));
        return new RentalResource($rental->fresh());
    }

    /**
     * POST /api/rentals/{rental}/renew
     */
    public function renew(RenewRentalRequest $request, Rental $rental)
    {
        $renewal = $this->rentalService->renewRental($rental, $request->validated(), auth()->user());
        return new RentalResource($rental->fresh('client', 'locker', 'renewals', 'invoices'));
    }

    /**
     * POST /api/rentals/{rental}/cancel
     */
    public function cancel(Request $request, Rental $rental)
    {
        $request->validate(['reason' => 'nullable|string|max:500']);
        $this->rentalService->cancelRental($rental, $request->reason, auth()->user());
        return new RentalResource($rental->fresh());
    }

    /**
     * POST /api/rentals/{rental}/key-return
     */
    public function keyReturn(Rental $rental)
    {
        if ($rental->key_status !== 'with_client') {
            return response()->json(['message' => 'Key is not currently with the client.'], 422);
        }

        $rental->update([
            'key_status'       => 'returned',
            'key_returned_at'  => now(),
            'key_returned_by'  => auth()->id(),
        ]);

        return new RentalResource($rental->fresh());
    }

    /**
     * POST /api/rentals/{rental}/lost-key
     */
    public function reportLostKey(Request $request, Rental $rental)
    {
        $request->validate([
            'replacement_fee' => 'required|numeric|min:0',
            'notes'           => 'nullable|string',
        ]);

        $incident = LostKeyIncident::create([
            'rental_id'       => $rental->id,
            'reported_by'     => auth()->id(),
            'replacement_fee' => $request->replacement_fee,
            'fee_charged'     => $request->replacement_fee > 0,
            'notes'           => $request->notes,
        ]);

        $rental->update(['key_status' => 'lost']);

        return response()->json([
            'message'  => 'Lost key incident recorded.',
            'incident' => $incident,
        ]);
    }

    /**
     * GET /api/rentals/{rental}/invoice
     */
    public function invoice(Rental $rental)
    {
        $invoice = $rental->invoices()->latest()->first();
        if (! $invoice) {
            return response()->json(['message' => 'No invoice found for this rental.'], 404);
        }
        return response()->json(['invoice' => $invoice->load('payments.paymentMethod')]);
    }

    /**
     * GET /api/rentals/{rental}/invoice/pdf
     */
    public function invoicePdf(Rental $rental)
    {
        $invoice = $rental->invoices()->latest()->firstOrFail();
        $invoice->load('rental.locker.category', 'rental.client', 'payments.paymentMethod');

        $pdf = Pdf::loadView('pdf.invoice', compact('invoice'));
        return $pdf->download("invoice-{$invoice->invoice_number}.pdf");
    }
}
