<?php

namespace App\Http\Controllers;

use App\Models\DeliveryNote;
use App\Models\Order;
use App\Models\Setting;
use App\Models\Vehicle;
use Illuminate\Http\Request;

class DeliveryNoteController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    private function authorizeDeliveryNoteAccess(Request $request): void
    {
        $user = $request->user();

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

        if (method_exists($user, 'isDeveloper') && $user->isDeveloper()) {
            return;
        }

        if (
            method_exists($user, 'can') && (
                $user->can('create orders') ||
                $user->can('view orders') ||
                $user->can('print spk') ||
                $user->can('process payments')
            )
        ) {
            return;
        }

        abort(403, 'Anda tidak memiliki akses surat jalan.');
    }

    public function index(Request $request)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $query = DeliveryNote::with(['order', 'vehicle', 'creator']);

        if ($request->filled('search')) {
            $search = trim((string) $request->search);

            $query->where(function ($q) use ($search) {
                $q->where('number', 'like', "%{$search}%")
                    ->orWhere('recipient_name', 'like', "%{$search}%")
                    ->orWhere('vehicle_name', 'like', "%{$search}%")
                    ->orWhere('plate_number', 'like', "%{$search}%")
                    ->orWhereHas('order', function ($orderQuery) use ($search) {
                        $orderQuery->where('invoice_number', 'like', "%{$search}%")
                            ->orWhere('customer_name', 'like', "%{$search}%");
                    });
            });
        }

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

        return view('pages.delivery-notes.index', [
            'title' => 'Surat Jalan',
            'deliveryNotes' => $query->latest()->paginate(30)->withQueryString(),
        ]);
    }

    public function create(Request $request)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $order = null;

        if ($request->filled('order_id')) {
            $order = Order::with(['customer', 'items'])->findOrFail($request->integer('order_id'));
        }

        $orders = Order::query()
            ->where('is_cancelled', false)
            ->with('items')
            ->latest()
            ->limit(200)
            ->get();

        $vehicles = Vehicle::active()->orderBy('name')->get();

        return view('pages.delivery-notes.create', [
            'title' => 'Buat Surat Jalan',
            'deliveryNote' => new DeliveryNote([
                'delivery_date' => now(),
                'recipient_name' => $order?->customer_name,
                'recipient_phone' => $order?->customer_phone,
            ]),
            'selectedOrder' => $order,
            'orders' => $orders,
            'vehicles' => $vehicles,
        ]);
    }

    public function store(Request $request)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $validated = $request->validate([
            'order_id' => ['required', 'exists:orders,id'],
            'vehicle_id' => ['nullable', 'exists:vehicles,id'],
            'recipient_name' => ['nullable', 'string', 'max:255'],
            'recipient_phone' => ['nullable', 'string', 'max:50'],
            'recipient_address' => ['nullable', 'string', 'max:2000'],
            'driver_name' => ['nullable', 'string', 'max:255'],
            'driver_phone' => ['nullable', 'string', 'max:50'],
            'vehicle_name' => ['nullable', 'string', 'max:255'],
            'plate_number' => ['nullable', 'string', 'max:50'],
            'delivery_date' => ['nullable', 'date'],
            'notes' => ['nullable', 'string', 'max:2000'],
        ]);

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

        if (!$order->isPaid() && !$order->is_credit) {
            return back()->withInput()->with('error', 'Surat jalan hanya bisa dibuat untuk order yang sudah lunas atau piutang.');
        }

        $vehicle = null;

        if (!empty($validated['vehicle_id'])) {
            $vehicle = Vehicle::find($validated['vehicle_id']);
        }

        $deliveryNote = DeliveryNote::create([
            'order_id' => $order->id,
            'vehicle_id' => $vehicle?->id,
            'recipient_name' => $validated['recipient_name'] ?? $order->customer_name,
            'recipient_phone' => $validated['recipient_phone'] ?? $order->customer_phone,
            'recipient_address' => $validated['recipient_address'] ?? null,
            'driver_name' => $validated['driver_name'] ?? $vehicle?->driver_name,
            'driver_phone' => $validated['driver_phone'] ?? $vehicle?->driver_phone,
            'vehicle_name' => $validated['vehicle_name'] ?? $vehicle?->name,
            'plate_number' => $validated['plate_number'] ?? $vehicle?->plate_number,
            'delivery_date' => $validated['delivery_date'] ?? now()->toDateString(),
            'notes' => $validated['notes'] ?? null,
            'created_by' => $request->user()->id,
        ]);

        return redirect()->route('delivery-notes.show', $deliveryNote)
            ->with('success', 'Surat jalan berhasil dibuat.');
    }

    public function show(Request $request, DeliveryNote $deliveryNote)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $deliveryNote->load(['order.items', 'order.customer', 'vehicle', 'creator']);

        return view('pages.delivery-notes.show', [
            'title' => 'Detail Surat Jalan ' . $deliveryNote->number,
            'deliveryNote' => $deliveryNote,
        ]);
    }

    public function edit(Request $request, DeliveryNote $deliveryNote)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $deliveryNote->load(['order', 'vehicle']);

        $orders = Order::query()
            ->where('is_cancelled', false)
            ->latest()
            ->limit(200)
            ->get();

        $vehicles = Vehicle::active()->orderBy('name')->get();

        return view('pages.delivery-notes.edit', [
            'title' => 'Edit Surat Jalan',
            'deliveryNote' => $deliveryNote,
            'orders' => $orders,
            'vehicles' => $vehicles,
        ]);
    }

    public function update(Request $request, DeliveryNote $deliveryNote)
    {
        $this->authorizeDeliveryNoteAccess($request);

        if ($deliveryNote->status === DeliveryNote::STATUS_CANCELLED) {
            return redirect()->route('delivery-notes.show', $deliveryNote)
                ->with('error', 'Surat jalan yang dibatalkan tidak bisa diedit.');
        }

        $validated = $request->validate([
            'order_id' => ['required', 'exists:orders,id'],
            'vehicle_id' => ['nullable', 'exists:vehicles,id'],
            'recipient_name' => ['nullable', 'string', 'max:255'],
            'recipient_phone' => ['nullable', 'string', 'max:50'],
            'recipient_address' => ['nullable', 'string', 'max:2000'],
            'driver_name' => ['nullable', 'string', 'max:255'],
            'driver_phone' => ['nullable', 'string', 'max:50'],
            'vehicle_name' => ['nullable', 'string', 'max:255'],
            'plate_number' => ['nullable', 'string', 'max:50'],
            'delivery_date' => ['nullable', 'date'],
            'status' => ['required', 'in:draft,printed,delivered,received,cancelled'],
            'notes' => ['nullable', 'string', 'max:2000'],
        ]);

        $vehicle = !empty($validated['vehicle_id']) ? Vehicle::find($validated['vehicle_id']) : null;

        $deliveryNote->update([
            'order_id' => $validated['order_id'],
            'vehicle_id' => $vehicle?->id,
            'recipient_name' => $validated['recipient_name'] ?? null,
            'recipient_phone' => $validated['recipient_phone'] ?? null,
            'recipient_address' => $validated['recipient_address'] ?? null,
            'driver_name' => $validated['driver_name'] ?? $vehicle?->driver_name,
            'driver_phone' => $validated['driver_phone'] ?? $vehicle?->driver_phone,
            'vehicle_name' => $validated['vehicle_name'] ?? $vehicle?->name,
            'plate_number' => $validated['plate_number'] ?? $vehicle?->plate_number,
            'delivery_date' => $validated['delivery_date'] ?? null,
            'status' => $validated['status'],
            'notes' => $validated['notes'] ?? null,
        ]);

        return redirect()->route('delivery-notes.show', $deliveryNote)
            ->with('success', 'Surat jalan berhasil diperbarui.');
    }

    public function destroy(Request $request, DeliveryNote $deliveryNote)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $deliveryNote->update(['status' => DeliveryNote::STATUS_CANCELLED]);

        return redirect()->route('delivery-notes.index')
            ->with('success', 'Surat jalan berhasil dibatalkan.');
    }

    public function print(Request $request, DeliveryNote $deliveryNote)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $deliveryNote->load(['order.items', 'order.customer', 'vehicle', 'creator']);
        $deliveryNote->markPrinted();

        $paperSize = $request->query('paper', 'a4');

        if (!in_array($paperSize, ['a4', 'a5', '215x165'], true)) {
            $paperSize = 'a4';
        }

        return view('print.delivery-note', [
            'deliveryNote' => $deliveryNote,
            'order' => $deliveryNote->order,
            'shopName' => Setting::getShopName(),
            'shopAddress' => Setting::getShopAddress(),
            'shopPhone' => Setting::getShopPhone(),
            'shopLogo' => Setting::getShopLogo(),
            'printedAt' => now(),
            'paperSize' => $paperSize,
        ]);
    }

    public function markDelivered(Request $request, DeliveryNote $deliveryNote)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $deliveryNote->update(['status' => DeliveryNote::STATUS_DELIVERED]);

        return back()->with('success', 'Status surat jalan diubah menjadi dikirim.');
    }

    public function markReceived(Request $request, DeliveryNote $deliveryNote)
    {
        $this->authorizeDeliveryNoteAccess($request);

        $deliveryNote->update(['status' => DeliveryNote::STATUS_RECEIVED]);

        return back()->with('success', 'Status surat jalan diubah menjadi diterima.');
    }
}
