<?php

namespace App\Http\Controllers\Care;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Care\Concerns\ScopesToAccount;
use App\Models\Consultation;
use App\Models\InvestigationRequest;
use App\Models\InvestigationType;
use App\Models\Member;
use App\Services\Care\BranchContext;
use App\Services\Care\CareQueueBridge;
use App\Services\Care\CareQueueContexts;
use App\Services\Care\ConsultationReturnContext;
use App\Services\Care\InvestigationService;
use App\Services\Care\OrganizationResolver;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class InvestigationController extends Controller
{
    use ScopesToAccount;

    public function __construct(
        protected InvestigationService $investigations,
        protected CareQueueBridge $queueBridge,
        protected BranchContext $branchContext,
    ) {}

    public function index(Request $request): View
    {
        $this->authorizeAbility($request, 'lab.view');
        $organization = $this->organization($request);
        $member = $this->member($request);
        $branchId = $this->branchContext->resolve($request, $organization, $member);

        $requests = $this->investigations->list(
            $this->ownerRef($request),
            $organization->id,
            $request->only(['status', 'patient_id']),
            $branchId > 0 ? $branchId : null,
        );

        return view('care.lab.requests.index', [
            'organization' => $organization,
            'requests' => $requests,
            'statuses' => config('care.investigation_statuses'),
        ]);
    }

    public function queue(Request $request): View
    {
        $this->authorizeAbility($request, 'lab.manage');
        $organization = $this->organization($request);
        $member = $this->member($request);
        $branches = $this->branchContext->branches($request, $organization, $member);
        $branchId = $this->branchContext->resolve($request, $organization, $member);
        $status = $request->input('status');

        $queue = $branchId
            ? $this->investigations->workQueue($this->ownerRef($request), $branchId, $status)
            : collect();

        return view('care.lab.queue.index', [
            'organization' => $organization,
            'branches' => $branches,
            'branchId' => $branchId,
            'canSwitchBranch' => $this->branchContext->canSwitch($member),
            'status' => $status,
            'queue' => $queue,
            'statuses' => config('care.investigation_statuses'),
            'members' => Member::owned($this->ownerRef($request))
                ->where('organization_id', $organization->id)
                ->orderBy('role')
                ->get(),
            'queueIntegration' => $branchId
                ? $this->queueBridge->listMeta($organization, CareQueueContexts::LABORATORY, $branchId)
                : ['enabled' => false],
        ]);
    }

    public function callNext(Request $request): RedirectResponse
    {
        $this->authorizeAbility($request, 'lab.manage');
        $organization = $this->organization($request);
        $member = $this->member($request);
        $branchId = $this->branchContext->resolve($request, $organization, $member);
        abort_unless($branchId > 0, 422);
        abort_unless($this->queueBridge->isEnabled($organization), 404);

        $result = $this->queueBridge->callNext($organization, CareQueueContexts::LABORATORY, $branchId, $member);
        $ticket = $result['ticket'] ?? null;
        if (! $ticket) {
            return back()->with('info', 'No lab work waiting at your laboratory service point.');
        }

        return back()->with('success', 'Called '.$ticket['ticket_number'].'.');
    }

    public function serve(Request $request, InvestigationRequest $investigation): RedirectResponse
    {
        $this->authorizeAbility($request, 'lab.manage');
        $this->authorizeInvestigation($request, $investigation);
        $organization = $this->organization($request);
        abort_unless($this->queueBridge->isEnabled($organization), 404);

        $ticket = $this->queueBridge->serve($organization, $investigation);
        if (! $ticket) {
            return back()->with('error', 'Could not serve lab ticket.');
        }

        return back()->with('success', 'Now serving '.$ticket['ticket_number'].'.');
    }

    public function requestFromConsultation(Request $request, Consultation $consultation): RedirectResponse
    {
        $this->authorizeAbility($request, 'investigations.request');
        $this->authorizeConsultation($request, $consultation);

        $validated = $request->validate([
            'investigation_type_ids' => ['required', 'array', 'min:1'],
            'investigation_type_ids.*' => ['integer', 'exists:care_investigation_types,id'],
            'clinical_notes' => ['nullable', 'string', 'max:2000'],
            'priority' => ['nullable', 'string', 'in:routine,urgent'],
        ]);

        $this->investigations->requestFromConsultation(
            $consultation,
            $this->ownerRef($request),
            $validated['investigation_type_ids'],
            $validated['clinical_notes'] ?? null,
            $validated['priority'] ?? 'routine',
            $this->ownerRef($request),
        );

        return back()->with('success', 'Investigation request(s) submitted.');
    }

    public function show(Request $request, InvestigationRequest $investigation): View
    {
        $this->authorizeAbility($request, 'lab.view');
        $this->authorizeInvestigation($request, $investigation);

        $investigation->load([
            'patient', 'investigationType', 'practitioner', 'branch',
            'result.values', 'result.attachments', 'assignedMember',
            'consultation.patient', 'consultation.appointment',
        ]);

        $canManage = app(\App\Services\Care\CarePermissions::class)
            ->can($this->member($request), 'lab.manage');
        $canViewResults = app(\App\Services\Care\CarePermissions::class)
            ->can($this->member($request), 'lab.results.view');

        $return = app(ConsultationReturnContext::class);

        return view('care.lab.requests.show', [
            'investigation' => $investigation,
            'statuses' => config('care.investigation_statuses'),
            'canManage' => $canManage,
            'canViewResults' => $canViewResults,
            'returnConsultation' => $return->resolve($request, (int) $investigation->patient_id)
                ?? $return->resolveLinked($request, $investigation->consultation),
        ]);
    }

    public function collectSample(Request $request, InvestigationRequest $investigation): RedirectResponse
    {
        $this->authorizeAbility($request, 'lab.manage');
        $this->authorizeInvestigation($request, $investigation);

        $validated = $request->validate(['sample_barcode' => ['nullable', 'string', 'max:100']]);

        $this->investigations->collectSample(
            $investigation,
            $this->ownerRef($request),
            $validated['sample_barcode'] ?? null,
            $this->ownerRef($request),
        );

        return back()->with('success', 'Sample collected.');
    }

    public function startProcessing(Request $request, InvestigationRequest $investigation): RedirectResponse
    {
        $this->authorizeAbility($request, 'lab.manage');
        $this->authorizeInvestigation($request, $investigation);

        $validated = $request->validate(['assigned_member_id' => ['nullable', 'integer', 'exists:care_members,id']]);

        $this->investigations->startProcessing(
            $investigation,
            $this->ownerRef($request),
            $validated['assigned_member_id'] ?? null,
            $this->ownerRef($request),
        );

        return redirect()->route('care.lab.requests.show', $investigation)
            ->with('success', 'Processing started.');
    }

    public function enterResults(Request $request, InvestigationRequest $investigation): RedirectResponse
    {
        $this->authorizeAbility($request, 'lab.manage');
        $this->authorizeInvestigation($request, $investigation);

        $validated = $request->validate([
            'value' => ['nullable', 'string', 'max:255'],
            'result_summary' => ['nullable', 'string', 'max:5000'],
            'interpretation' => ['nullable', 'string', 'max:5000'],
            'values' => ['nullable', 'array'],
            'values.*.parameter' => ['nullable', 'string', 'max:255'],
            'values.*.value' => ['nullable', 'string', 'max:255'],
            'attachments' => ['nullable', 'array'],
            'attachments.*' => ['file', 'max:10240', 'mimes:pdf,jpeg,png,jpg,webp'],
        ]);

        $this->investigations->enterResults(
            $investigation,
            $this->ownerRef($request),
            $validated,
            $this->ownerRef($request),
        );

        return back()->with('success', 'Results submitted for review.');
    }

    public function approve(Request $request, InvestigationRequest $investigation): RedirectResponse
    {
        $this->authorizeAbility($request, 'pathology.result.approve');
        $this->authorizeInvestigation($request, $investigation);

        $this->investigations->approve($investigation, $this->ownerRef($request), $this->ownerRef($request));

        return back()->with('success', 'Results approved.');
    }

    public function deliver(Request $request, InvestigationRequest $investigation): RedirectResponse
    {
        $this->authorizeAbility($request, 'lab.manage');
        $this->authorizeInvestigation($request, $investigation);

        $this->investigations->deliver($investigation, $this->ownerRef($request), $this->ownerRef($request));

        return back()->with('success', 'Results delivered to patient record.');
    }

    public function cancel(Request $request, InvestigationRequest $investigation): RedirectResponse
    {
        $this->authorizeAbility($request, 'lab.manage');
        $this->authorizeInvestigation($request, $investigation);

        $this->investigations->cancel($investigation, $this->ownerRef($request), $this->ownerRef($request));

        return back()->with('success', 'Investigation cancelled.');
    }

    protected function authorizeConsultation(Request $request, Consultation $consultation): void
    {
        $this->authorizeOwner($request, $consultation);
        $consultation->loadMissing('visit');
        abort_unless($consultation->visit->organization_id === $this->organization($request)->id, 404);
    }

    protected function authorizeInvestigation(Request $request, InvestigationRequest $investigation): void
    {
        $this->authorizeOwner($request, $investigation);
        abort_unless($investigation->organization_id === $this->organization($request)->id, 404);

        $branchId = app(OrganizationResolver::class)->branchScope($this->member($request));
        if ($branchId !== null && $investigation->branch_id !== $branchId) {
            abort(404);
        }
    }
}
