<?php

namespace Modules\ClinicLab\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\ClinicLab\Entities\CllSpecimen;
use Modules\ClinicLab\Entities\Services\SpecimenService;
use Modules\LabCore\Entities\LabWorklist;

/**
 * Specimen tracking screens — /clinic-lab/specimens.
 * Permission-gated on cliniclab.specimen.manage. business_id scoped.
 */
class CllSpecimenController extends Controller
{
    protected function guard(): void
    {
        if (! auth()->user() || ! auth()->user()->can('cliniclab.specimen.manage')) {
            abort(403, 'Unauthorized action.');
        }
    }

    protected function bizId()
    {
        return request()->session()->get('user.business_id');
    }

    public function index()
    {
        $this->guard();
        $specimens = CllSpecimen::forBusiness($this->bizId())
            ->with(['worklist', 'catalog'])
            ->orderByDesc('id')->limit(200)->get();
        return view('clinicLab::specimens.index', compact('specimens'));
    }

    /** Generate a specimen from a worklist row (the "Generate specimen" action). */
    public function generate($worklistId, SpecimenService $service)
    {
        $this->guard();
        $worklist = LabWorklist::where('business_id', $this->bizId())->findOrFail($worklistId);
        $specimen = $service->generateFromWorklist($worklist);

        return redirect()->route('clinic-lab.specimens.show', $specimen->id)
            ->with('status', ['success' => 1, 'msg' => 'Specimen ' . $specimen->specimen_no . ' generated.']);
    }

    public function show($id)
    {
        $this->guard();
        $specimen = CllSpecimen::forBusiness($this->bizId())->with(['worklist', 'catalog'])->findOrFail($id);
        return view('clinicLab::specimens.show', compact('specimen'));
    }

    /** Printable barcode label. */
    public function barcode($id)
    {
        $this->guard();
        $specimen = CllSpecimen::forBusiness($this->bizId())->findOrFail($id);
        return view('clinicLab::specimens.barcode', compact('specimen'));
    }

    public function collect($id, SpecimenService $service)
    {
        $this->guard();
        $specimen = CllSpecimen::forBusiness($this->bizId())->findOrFail($id);
        $service->collect($specimen);
        return back()->with('status', ['success' => 1, 'msg' => 'Marked collected.']);
    }

    public function receive($id, SpecimenService $service)
    {
        $this->guard();
        $specimen = CllSpecimen::forBusiness($this->bizId())->findOrFail($id);
        $service->receive($specimen);
        return back()->with('status', ['success' => 1, 'msg' => 'Marked received.']);
    }

    public function process($id, SpecimenService $service)
    {
        $this->guard();
        $specimen = CllSpecimen::forBusiness($this->bizId())->findOrFail($id);
        $service->transition($specimen, 'processing');
        return back()->with('status', ['success' => 1, 'msg' => 'Marked processing.']);
    }

    public function reject($id, Request $request, SpecimenService $service)
    {
        $this->guard();
        $data = $request->validate([
            'rejected_reason' => 'required|in:hemolyzed,clotted,insufficient_volume,wrong_container,mislabeled,expired,other',
            'rejection_notes' => 'nullable|string|max:255',
        ]);
        $specimen = CllSpecimen::forBusiness($this->bizId())->findOrFail($id);
        $service->reject($specimen, $data['rejected_reason'], $data['rejection_notes'] ?? null);
        return back()->with('status', ['success' => 1, 'msg' => 'Specimen rejected — the ordering context was notified.']);
    }
}
