<?php

namespace App\Jobs\Concerns;

use App\Providers\TenancyServiceProvider;
use App\Services\CurrentContext;
use RuntimeException;

/**
 * Explicit, self-documenting tenant binding for a specific job instance.
 *
 * Note: {@see TenancyServiceProvider} already stamps every
 * dispatched job's payload with the current tenant_id (or nothing, if
 * dispatched from central/CLI context) and rebinds {@see CurrentContext}
 * — via setTenant(), or markCentral() when absent — before `handle()` runs.
 * That queue-boundary propagation is automatic and requires no per-job
 * wiring; a job with no tenant in its payload correctly runs unscoped
 * (central), not ambiguously.
 *
 * This trait is for the narrower case: a job that is only ever meaningful
 * for one specific tenant (e.g. it was constructed with a tenant/record
 * reference directly, not dispatched from within that tenant's request
 * context) and must fail loudly rather than silently run unscoped if that
 * tenant was never captured. Call {@see captureTenantContext()} in the
 * constructor, then wrap the body of `handle()` in {@see withTenantContext()}.
 */
trait WithTenantContext
{
    protected ?int $tenantContextId = null;

    /**
     * Snapshot the current tenant id (or an explicit one) at construction/dispatch
     * time so it survives queue serialization.
     */
    public function captureTenantContext(?int $tenantId = null): void
    {
        $this->tenantContextId = $tenantId ?? app(CurrentContext::class)->tenantId();
    }

    /**
     * Run the job body with CurrentContext bound to the captured tenant.
     */
    protected function withTenantContext(callable $callback): mixed
    {
        if ($this->tenantContextId === null) {
            throw new RuntimeException(
                static::class.' has no captured tenant context — call captureTenantContext() '
                .'in the constructor (or explicitly pass a tenant id) before dispatch.',
            );
        }

        return app(CurrentContext::class)->runForTenant($this->tenantContextId, $callback);
    }
}
