<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreLoanRequest;
use App\Models\AssetUnit;
use App\Models\Item;
use App\Models\Loan;
use App\Models\LoanLine;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class LoanController extends Controller
{
    public function index(): View
    {
        return view('loans.index', [
            'loans' => Loan::query()->with('lines.item', 'lines.assetUnit')->latest('loaned_at')->paginate(15),
        ]);
    }

    public function create(): View
    {
        return view('loans.form', [
            'loan' => new Loan(['loaned_at' => now()->toDateString()]),
            'items' => Item::query()->with('stock', 'location')->orderBy('name')->get(),
            'assetUnits' => AssetUnit::query()->with('item.location')->where('status', 'available')->orderBy('code')->get(),
            'action' => route('loans.store'),
            'method' => 'POST',
            'isReturnForm' => false,
        ]);
    }

    public function store(StoreLoanRequest $request): RedirectResponse
    {
        DB::transaction(function () use ($request) {
            $validated = $request->validated();
            $lines = collect($validated['lines'])
                ->filter(fn ($line) => ! empty($line['item_id']) || ! empty($line['asset_unit_id']))
                ->values();

            if ($lines->isEmpty()) {
                throw ValidationException::withMessages([
                    'lines' => 'Pilih minimal satu barang atau unit untuk dipinjam.',
                ]);
            }

            $loan = Loan::query()->create([
                'user_id' => $request->user()?->id,
                'borrower_name' => $validated['borrower_name'],
                'borrower_phone' => $validated['borrower_phone'] ?? null,
                'borrower_unit' => $validated['borrower_unit'] ?? null,
                'loaned_at' => $validated['loaned_at'],
                'due_at' => $validated['due_at'] ?? null,
                'notes' => $validated['notes'] ?? null,
                'status' => 'active',
            ]);

            foreach ($lines as $line) {
                if (! empty($line['asset_unit_id'])) {
                    $unit = AssetUnit::query()->with('item')->findOrFail($line['asset_unit_id']);
                    abort_if($unit->status !== 'available', 422, 'Ada unit yang sedang tidak tersedia untuk dipinjam.');

                    LoanLine::query()->create([
                        'loan_id' => $loan->id,
                        'item_id' => $unit->item_id,
                        'asset_unit_id' => $unit->id,
                        'item_name_snapshot' => $unit->name ?: $unit->item->name,
                        'quantity' => 1,
                        'condition_on_loan' => $line['condition_on_loan'] ?? $unit->current_condition,
                        'notes' => $line['notes'] ?? null,
                    ]);

                    $unit->update(['status' => 'borrowed']);

                    continue;
                }

                $item = Item::query()->with('stock')->findOrFail($line['item_id']);
                abort_if(($item->stock?->available_quantity ?? 0) < $line['quantity'], 422, "Stok barang {$item->name} tidak mencukupi.");

                LoanLine::query()->create([
                    'loan_id' => $loan->id,
                    'item_id' => $item->id,
                    'item_name_snapshot' => $item->name,
                    'quantity' => $line['quantity'],
                    'condition_on_loan' => $line['condition_on_loan'] ?? 'good',
                    'notes' => $line['notes'] ?? null,
                ]);

                $item->stock()->update([
                    'available_quantity' => $item->stock->available_quantity - $line['quantity'],
                    'borrowed_quantity' => $item->stock->borrowed_quantity + $line['quantity'],
                ]);
            }
        });

        return redirect()->route('loans.index')->with('status', 'Peminjaman berhasil dicatat.');
    }

    public function edit(Loan $loan): View
    {
        return view('loans.form', [
            'loan' => $loan->load('lines.item', 'lines.assetUnit'),
            'items' => collect(),
            'assetUnits' => collect(),
            'action' => route('loans.update', $loan),
            'method' => 'PUT',
            'isReturnForm' => true,
        ]);
    }

    public function update(Request $request, Loan $loan): RedirectResponse
    {
        $validated = $request->validate([
            'returned_at' => ['required', 'date'],
            'lines' => ['required', 'array'],
            'lines.*.returned_quantity' => ['required', 'integer', 'min:0'],
            'lines.*.condition_on_return' => ['nullable', 'in:good,minor,major'],
        ]);

        DB::transaction(function () use ($loan, $validated) {
            $loan->load('lines.item.stock', 'lines.assetUnit');

            foreach ($loan->lines as $line) {
                $linePayload = $validated['lines'][$line->id] ?? null;

                if (! $linePayload) {
                    continue;
                }

                $returnedQuantity = min((int) $linePayload['returned_quantity'], $line->quantity);
                $increment = max($returnedQuantity - $line->returned_quantity, 0);

                if ($increment > 0 && $line->assetUnit) {
                    $line->assetUnit->update([
                        'status' => 'available',
                        'current_condition' => $linePayload['condition_on_return'] ?? $line->assetUnit->current_condition,
                    ]);
                }

                if ($increment > 0 && $line->item && ! $line->assetUnit && $line->item->stock) {
                    $line->item->stock->update([
                        'available_quantity' => $line->item->stock->available_quantity + $increment,
                        'borrowed_quantity' => max($line->item->stock->borrowed_quantity - $increment, 0),
                    ]);
                }

                $line->update([
                    'returned_quantity' => $returnedQuantity,
                    'condition_on_return' => $linePayload['condition_on_return'] ?? $line->condition_on_return,
                ]);
            }

            $loan->refresh()->load('lines');
            $fullyReturned = $loan->lines->every(fn (LoanLine $line) => $line->returned_quantity >= $line->quantity);

            $loan->update([
                'returned_at' => $validated['returned_at'],
                'status' => $fullyReturned ? 'returned' : 'active',
            ]);
        });

        return redirect()->route('loans.index')->with('status', 'Pengembalian berhasil diproses.');
    }

    public function destroy(Loan $loan): RedirectResponse
    {
        $loan->delete();

        return redirect()->route('loans.index')->with('status', 'Data peminjaman berhasil dihapus.');
    }
}
