<?php
namespace App\Http\Controllers;
use App\Models as M;
use App\Services\ApprovalService;
use App\Services\SequenceService;
use App\Support\CrudRegistry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class PurchaseRequisitionController extends Controller {
    public function index(Request $r) { return app(CrudController::class)->index($r, 'purchase-requisitions'); }
    public function show(int $id) { return app(CrudController::class)->show('purchase-requisitions', $id); }
    public function create() {
        $this->need('purchase.create');
        return view('docs.purchase-requisition.form', $this->formData(new M\PurchaseRequisition(['pr_date' => date('Y-m-d')])));
    }
    public function store(Request $r) {
        $this->need('purchase.create');
        $d = $this->validated($r);
        $pr = DB::transaction(function () use ($d) {
            $pr = M\PurchaseRequisition::create($d['head'] + ['pr_no' => SequenceService::next('purchase_requisition'), 'status' => 'submitted', 'requested_by' => Auth::id()]);
            foreach ($d['lines'] as $l) $pr->lines()->create($l);
            ApprovalService::request('purchase_requisition', $pr->id, $pr->pr_no);
            return $pr;
        });
        return redirect()->route('purchase-requisitions.show', $pr)->with('success', 'Requisition '.$pr->pr_no.' submitted for approval.');
    }
    public function edit(int $id) {
        $this->need('purchase.edit');
        $pr = M\PurchaseRequisition::with('lines')->findOrFail($id);
        abort_unless(in_array($pr->status, ['draft', 'submitted']), 403, 'Approved requisitions cannot be edited.');
        return view('docs.purchase-requisition.form', $this->formData($pr));
    }
    public function update(Request $r, int $id) {
        $this->need('purchase.edit');
        $pr = M\PurchaseRequisition::findOrFail($id);
        abort_unless(in_array($pr->status, ['draft', 'submitted']), 403, 'Approved requisitions cannot be edited.');
        $d = $this->validated($r);
        DB::transaction(function () use ($pr, $d) {
            $pr->update($d['head']);
            $pr->lines()->delete();
            foreach ($d['lines'] as $l) $pr->lines()->create($l);
        });
        return redirect()->route('purchase-requisitions.show', $pr)->with('success', 'Requisition updated.');
    }
    public function destroy(int $id) {
        $this->need('purchase.delete');
        $pr = M\PurchaseRequisition::findOrFail($id);
        abort_unless(in_array($pr->status, ['draft', 'submitted']), 403, 'Approved requisitions cannot be deleted.');
        $pr->delete();
        return redirect()->route('purchase-requisitions.index')->with('success', 'Requisition deleted.');
    }
    public function convert(int $id) {
        $this->need('purchase.create');
        $pr = M\PurchaseRequisition::findOrFail($id);
        abort_unless($pr->status === 'approved', 403, 'Only approved requisitions convert to LPO.');
        return redirect()->route('purchase-orders.create', ['from_pr' => $pr->id]);
    }
    protected function validated(Request $r): array {
        $head = $r->validate(['pr_date' => 'required|date', 'department' => 'nullable|max:60', 'quarry_id' => 'nullable|exists:quarries,id',
            'project_id' => 'nullable|exists:projects,id', 'required_date' => 'nullable|date', 'purpose' => 'nullable|max:255',
            'lines' => 'required|array|min:1', 'lines.*.item_id' => 'nullable|exists:stock_items,id', 'lines.*.description' => 'required|max:255',
            'lines.*.qty' => 'required|numeric|min:0.001', 'lines.*.unit_id' => 'nullable|exists:units,id', 'lines.*.estimated_rate' => 'nullable|numeric|min:0']);
        $lines = $head['lines']; unset($head['lines']);
        return ['head' => $head, 'lines' => $lines];
    }
    protected function formData(M\PurchaseRequisition $pr): array {
        return ['record' => $pr, 'isNew' => !$pr->exists, 'cfg' => CrudRegistry::get('purchase-requisitions'), 'key' => 'purchase-requisitions',
            'docNo' => $pr->exists ? $pr->pr_no : SequenceService::peek('purchase_requisition'),
            'quarries' => M\Quarry::orderBy('name')->get(), 'projects' => M\Project::orderBy('code')->get(),
            'items' => M\StockItem::where('is_active', true)->orderBy('name')->get(), 'units' => M\Unit::orderBy('name')->get()];
    }
}
