<?php

namespace Modules\VetClinic\Entities\Services;

use Modules\VetClinic\Entities\VcDoctor;
use Modules\VetClinic\Entities\VcRoleSetting;

/**
 * Resolves per-role visibility scopes for the current user. Today it answers
 * one question — should the calendar / appointment list be limited to the
 * doctor the user is mapped to? — but it's structured so more scopes can
 * follow the same shape.
 */
class VcRoleScopeService
{
    /** request-lifetime cache: "userId:businessId" => int|null|false (false = computing) */
    private static array $cache = [];

    /**
     * @return int|null
     *   null  → no scope (the user sees every doctor's appointments)
     *   0     → user holds a role with scope='own' but is NOT mapped to any
     *           VcDoctor row, so we fail-closed and return zero rows
     *   int>0 → scope to this doctor_id
     */
    public static function appointmentDoctorScope($user, $businessId): ?int
    {
        if (!$user || !$businessId) {
            return null;
        }
        $key = $user->id . ':' . $businessId;
        if (array_key_exists($key, self::$cache)) {
            return self::$cache[$key];
        }

        try {
            $roleIds = $user->roles->pluck('id')->all();
            if (empty($roleIds)) {
                return self::$cache[$key] = null;
            }
            $scoped = VcRoleSetting::where('business_id', $businessId)
                ->whereIn('role_id', $roleIds)
                ->where('key', 'appointment_scope')
                ->where('value', 'own')
                ->exists();
            if (!$scoped) {
                return self::$cache[$key] = null;
            }
            $doctorId = VcDoctor::where('business_id', $businessId)
                ->where('user_id', $user->id)
                ->value('id');
            // 0 → fail-closed when the user holds a scoped role but has no
            // doctor record yet. Better to show nothing than to show all.
            return self::$cache[$key] = (int) ($doctorId ?: 0);
        } catch (\Throwable $e) {
            return self::$cache[$key] = null;
        }
    }
}
