<?php

namespace App\Services\Care;

use App\Models\Consultation;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

/**
 * Preserves "serving from consultation" context when doctors navigate to nested
 * forms (prescriptions, assessments, lab requests, pathways, bills).
 *
 * Preference order: explicit ?from_consultation= query → session remembered on
 * consultation show. Direct access without either shows no consultation chrome.
 */
class ConsultationReturnContext
{
    public const QUERY_KEY = 'from_consultation';

    public const SESSION_KEY = 'care.from_consultation';

    public function remember(Consultation $consultation): void
    {
        if ($consultation->status === Consultation::STATUS_COMPLETED) {
            $this->forget();

            return;
        }

        session([self::SESSION_KEY => $consultation->uuid]);
    }

    public function forget(): void
    {
        session()->forget(self::SESSION_KEY);
    }

    public function uuidFrom(Request $request): ?string
    {
        foreach ([
            $request->query(self::QUERY_KEY),
            $request->input(self::QUERY_KEY),
            session(self::SESSION_KEY),
        ] as $candidate) {
            if (is_string($candidate) && Str::isUuid($candidate)) {
                return $candidate;
            }
        }

        return null;
    }

    /**
     * Capture an explicit from_consultation posted/queried value into session
     * so subsequent redirects keep the serving flow.
     */
    public function capture(Request $request): void
    {
        $uuid = $request->query(self::QUERY_KEY) ?? $request->input(self::QUERY_KEY);
        if (is_string($uuid) && Str::isUuid($uuid)) {
            session([self::SESSION_KEY => $uuid]);
        }
    }

    public function resolve(Request $request, ?int $patientId = null): ?Consultation
    {
        $this->capture($request);

        $uuid = $this->uuidFrom($request);
        if ($uuid === null) {
            return null;
        }

        $consultation = Consultation::query()
            ->where('uuid', $uuid)
            ->with(['patient', 'appointment'])
            ->first();

        if (! $consultation) {
            return null;
        }

        if ($patientId !== null && (int) $consultation->patient_id !== $patientId) {
            return null;
        }

        return $consultation;
    }

    /**
     * Resolve from an explicit linked consultation (e.g. prescription.consultation)
     * only when the doctor is already in a serving flow for that consultation.
     */
    public function resolveLinked(Request $request, ?Consultation $linked): ?Consultation
    {
        if (! $linked) {
            return null;
        }

        $active = $this->resolve($request, (int) $linked->patient_id);
        if ($active && $active->id === $linked->id) {
            return $active;
        }

        // Nested under consultation route (create prescription) or still in progress
        // with an explicit query/session match already handled above. For linked
        // records opened mid-flow without query (POST redirect), prefer the linked
        // consultation when session matches its uuid.
        $uuid = $this->uuidFrom($request);
        if ($uuid !== null && $linked->uuid === $uuid) {
            $linked->loadMissing(['patient', 'appointment']);

            return $linked;
        }

        return null;
    }

    /**
     * @return array{from_consultation: string}
     */
    public function query(Consultation $consultation): array
    {
        return [self::QUERY_KEY => $consultation->uuid];
    }

    public function withQuery(string $url, Consultation $consultation): string
    {
        $separator = str_contains($url, '?') ? '&' : '?';

        return $url.$separator.self::QUERY_KEY.'='.urlencode($consultation->uuid);
    }

    /**
     * Route parameters to keep return context on redirects (empty when none).
     *
     * @return array<string, string>
     */
    public function routeQuery(Request $request): array
    {
        $this->capture($request);
        $uuid = $this->uuidFrom($request);

        return $uuid ? [self::QUERY_KEY => $uuid] : [];
    }
}
