<?php

namespace App\Services\Care\Workflow;

use App\Models\InvestigationRequest;
use App\Models\Organization;
use App\Models\Prescription;
use App\Models\Visit;
use App\Models\VisitStageAdvance;
use App\Services\Care\AuditLogger;
use App\Services\Care\CareQueueBridge;
use App\Services\Care\CareQueueContexts;
use App\Services\Care\VisitService;

/**
 * Advances a visit when the clinical entity backing its current stage is
 * complete. Multi-item lab/imaging/pharmacy stages wait for all sibling work.
 */
class WorkflowStageCompletionService
{
    public function __construct(
        protected WorkflowEngine $engine,
        protected WorkflowQueueGate $gate,
        protected WorkflowQueueReleaseService $queueRelease,
        protected CareQueueBridge $queue,
        protected VisitService $visits,
    ) {}

    public function complete(
        Organization $organization,
        Visit $visit,
        string $context,
        string $ownerRef,
        ?string $actorRef = null,
    ): ?VisitStageAdvance {
        if (! $this->gate->enabled($organization)) {
            return null;
        }

        $current = $this->engine->refreshGate($visit);
        $stage = $current?->stage;
        if ($stage === null || ! $this->contextMatches($stage->queue_context, $stage->type, $context)) {
            return null;
        }

        if ($this->hasOutstandingWork($visit, $context)) {
            return $current;
        }

        if (! $this->engine->canAdvance($visit)) {
            return $current;
        }

        $next = $this->engine->advance($visit);
        if ($next === null) {
            return null;
        }

        AuditLogger::record(
            $ownerRef,
            'visit.workflow_advanced',
            $visit->organization_id,
            $actorRef,
            VisitStageAdvance::class,
            $next->id,
            ['from_context' => $context, 'stage_code' => $next->stage_code, 'status' => $next->status],
        );

        if ($next->stage?->type === 'exit') {
            $this->visits->complete($visit, $ownerRef, $actorRef);
        } else {
            $this->queueRelease->releaseCurrent($organization, $visit);
        }

        return $next;
    }

    protected function hasOutstandingWork(Visit $visit, string $context): bool
    {
        if (in_array($context, [CareQueueContexts::LABORATORY, CareQueueContexts::IMAGING], true)) {
            return InvestigationRequest::query()
                ->where('visit_id', $visit->id)
                ->whereNotIn('status', [
                    InvestigationRequest::STATUS_COMPLETED,
                    InvestigationRequest::STATUS_DELIVERED,
                    InvestigationRequest::STATUS_CANCELLED,
                ])
                ->with('investigationType')
                ->get()
                ->contains(fn (InvestigationRequest $request) => $this->queue->contextForInvestigation($request) === $context);
        }

        if ($context === CareQueueContexts::PHARMACY) {
            return Prescription::query()
                ->where('visit_id', $visit->id)
                ->whereNotIn('status', [
                    Prescription::STATUS_DISPENSED,
                    Prescription::STATUS_CANCELLED,
                ])
                ->exists();
        }

        return false;
    }

    protected function contextMatches(?string $stageContext, string $stageType, string $context): bool
    {
        if ($stageContext === $context) {
            return true;
        }

        if ($stageType === 'payment' && $context === CareQueueContexts::BILLING) {
            return true;
        }

        return $stageType === 'consultation'
            && CareQueueContexts::isSpecialty($context)
            && $stageContext === CareQueueContexts::CONSULTATION;
    }
}
