<?php

namespace App\Services\Care;

use App\Models\Assessment;
use App\Models\AssessmentScore;
use App\Models\AssessmentTemplate;
use App\Models\Patient;
use App\Models\VitalSign;
use Illuminate\Support\Collection;

/**
 * Per-patient longitudinal trends (Layer 4) — free for all plans.
 * Org-wide multi-patient analytics remain Enterprise (KD-18).
 */
class OutcomeTrendService
{
    public const OUTCOME_TEMPLATE_CODE = 'outcome_core';

    /**
     * Completed outcome_core assessments newest-first with answer maps.
     *
     * @return Collection<int, array{assessment: Assessment, answers: array<string, mixed>, assessed_at: ?\Carbon\Carbon}>
     */
    public function outcomeSeries(Patient $patient, string $ownerRef, ?int $branchScope = null, int $limit = 50): Collection
    {
        $template = AssessmentTemplate::currentSystemByCode(self::OUTCOME_TEMPLATE_CODE);

        $query = Assessment::query()
            ->owned($ownerRef)
            ->where('patient_id', $patient->id)
            ->where('status', Assessment::STATUS_COMPLETED)
            ->with(['answers.question', 'template'])
            ->orderByDesc('assessed_at')
            ->orderByDesc('completed_at')
            ->limit($limit);

        if ($template) {
            $query->where('template_id', $template->id);
        } else {
            $query->whereHas('template', fn ($q) => $q->where('code', self::OUTCOME_TEMPLATE_CODE));
        }

        if ($branchScope !== null) {
            $query->where('branch_id', $branchScope);
        }

        return $query->get()->map(function (Assessment $assessment) {
            $answers = [];
            foreach ($assessment->answers as $answer) {
                if ($answer->question) {
                    $answers[$answer->question->code] = $answer->authoritativeValue($answer->question->answer_type);
                }
            }

            return [
                'assessment' => $assessment,
                'answers' => $answers,
                'assessed_at' => $assessment->assessed_at ?? $assessment->completed_at,
            ];
        });
    }

    /**
     * Recent instrument scores for chartable disease templates.
     *
     * @return Collection<int, AssessmentScore>
     */
    public function instrumentScores(
        Patient $patient,
        string $ownerRef,
        ?int $branchScope = null,
        ?string $templateCode = null,
        int $limit = 50,
    ): Collection {
        $query = AssessmentScore::query()
            ->owned($ownerRef)
            ->whereHas('assessment', function ($q) use ($patient, $branchScope) {
                $q->where('patient_id', $patient->id)
                    ->where('status', Assessment::STATUS_COMPLETED)
                    ->when($branchScope !== null, fn ($qq) => $qq->where('branch_id', $branchScope));
            })
            ->with(['assessment.template'])
            ->orderByDesc('computed_at')
            ->limit($limit);

        if ($templateCode) {
            $query->where('template_code', $templateCode);
        }

        return $query->get();
    }

    /**
     * Latest vitals from consultations (typed path — not outcome form).
     *
     * @return Collection<int, VitalSign>
     */
    public function recentVitals(Patient $patient, string $ownerRef, int $limit = 10): Collection
    {
        return VitalSign::query()
            ->where('owner_ref', $ownerRef)
            ->whereHas('consultation', fn ($q) => $q->where('patient_id', $patient->id))
            ->orderByDesc('recorded_at')
            ->limit($limit)
            ->get();
    }

    /**
     * Sparkline-friendly series for a single outcome numeric code (oldest → newest).
     *
     * @return list<array{date: string, value: float|int|null}>
     */
    public function numericOutcomeSeries(Patient $patient, string $ownerRef, string $questionCode, ?int $branchScope = null): array
    {
        $rows = $this->outcomeSeries($patient, $ownerRef, $branchScope)->reverse()->values();

        $out = [];
        foreach ($rows as $row) {
            $val = $row['answers'][$questionCode] ?? null;
            if ($val === null || $val === '') {
                continue;
            }
            $out[] = [
                'date' => $row['assessed_at']?->format('Y-m-d') ?? '',
                'value' => is_numeric($val) ? $val + 0 : null,
            ];
        }

        return $out;
    }
}
