using System.Text.Json.Nodes;
using Nexus.Api.Models;
using Nexus.Api.Services;

namespace Nexus.Api.Tests;

/// <summary>
/// Minimal live-RPC test double for consumers that only need the OpenClaw
/// agent/session inventory. Unsupported control-plane calls fail loudly so a
/// test cannot accidentally fall back to a fabricated legacy source.
/// </summary>
internal sealed class StubOpenClawControlService : IOpenClawControlService
{
    public StubOpenClawControlService(
        IReadOnlyList<OpenClawAgentDto>? agents = null,
        IReadOnlyList<OpenClawSessionDto>? sessions = null,
        bool connected = true)
    {
        Agents = agents ??
        [
            Agent("iris", "Iris", "openai/gpt-5.5", "/workspace/iris"),
            Agent("product-owner", "Product Owner", "openai/gpt-5.5", "/workspace-po"),
            Agent("programmer", "Programmer", "openai/gpt-5.4", "/workspace/programmer"),
            Agent("programmer-fast", "Programmer Fast", "openai/gpt-5.3-codex-spark", "/workspace/programmer-fast"),
            Agent("reviewer", "Reviewer", "openai/gpt-5.5", "/workspace/reviewer"),
            Agent("architekt", "Architekt", "openai/gpt-5.5", "/workspace/architekt")
        ];
        Sessions = sessions ?? [];
        Connected = connected;
    }

    public IReadOnlyList<OpenClawAgentDto> Agents { get; }
    public IReadOnlyList<OpenClawSessionDto> Sessions { get; }
    public bool Connected { get; }

    public OpenClawConnectionDto GetConnection()
        => new(
            State: Connected ? "connected" : "disconnected",
            Configured: true,
            CredentialConfigured: true,
            Connected: Connected,
            Endpoint: "ws://openclaw-gateway:18789",
            GatewayVersion: "2026.7.1",
            RequiredVersion: "2026.7.1",
            VersionPinned: true,
            VersionMatches: true,
            ProtocolVersion: 4,
            GrantedScopes: ["operator.read"],
            AdvertisedEvents: [],
            LastConnectedAt: Connected ? DateTimeOffset.UtcNow : null,
            LastEventAt: Connected ? DateTimeOffset.UtcNow : null,
            ReconnectAttempts: 0,
            Message: null,
            Recovery: null,
            CheckedAt: DateTimeOffset.UtcNow);

    public Task<OpenClawCollectionDto<OpenClawAgentDto>> GetAgentsAsync(
        CancellationToken cancellationToken = default)
        => Task.FromResult(Collection(Agents));

    public Task<OpenClawCollectionDto<OpenClawSessionDto>> GetSessionsAsync(
        int limit = 100,
        CancellationToken cancellationToken = default)
        => Task.FromResult(Collection<OpenClawSessionDto>(
            Sessions.Take(limit).ToArray()));

    public IReadOnlyList<OpenClawCapabilityDto> GetCapabilities() => [];
    public Task<OpenClawOverviewDto> GetOverviewAsync(CancellationToken cancellationToken = default)
        => Unsupported<OpenClawOverviewDto>();
    public Task<OpenClawCollectionDto<OpenClawTaskDto>> GetTasksAsync(
        int limit = 100,
        string? cursor = null,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawTaskDto>>();
    public Task<OpenClawCollectionDto<OpenClawCronJobDto>> GetCronJobsAsync(
        int limit = 100,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawCronJobDto>>();
    public Task<OpenClawCollectionDto<OpenClawCronJobDto>> GetCronJobsAsync(
        bool includeDisabled,
        int limit = 100,
        string? cursor = null,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawCronJobDto>>();
    public Task<OpenClawOperationDto<OpenClawCronJobDetailDto>> GetCronJobAsync(
        string jobId,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawOperationDto<OpenClawCronJobDetailDto>>();
    public Task<OpenClawCollectionDto<OpenClawCronRunDto>> GetCronRunsAsync(
        string jobId,
        int limit = 100,
        string? cursor = null,
        string? runId = null,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawCronRunDto>>();
    public Task<OpenClawCollectionDto<OpenClawApprovalDto>> GetApprovalsAsync(
        int limit = 100,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawApprovalDto>>();
    public Task<OpenClawCollectionDto<OpenClawActivityDto>> GetActivityAsync(
        int limit = 100,
        string? cursor = null,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawActivityDto>>();
    public Task<OpenClawCollectionDto<OpenClawModelDto>> GetModelsAsync(
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawModelDto>>();
    public Task<OpenClawCollectionDto<OpenClawModelAuthProviderDto>> GetModelAuthStatusAsync(
        bool refresh = false,
        CancellationToken cancellationToken = default)
        => Unsupported<OpenClawCollectionDto<OpenClawModelAuthProviderDto>>();
    public Task<OpenClawOperationDto<OpenClawTaskDto>> CancelTaskAsync(
        string taskId,
        string? reason,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<OpenClawTaskDto>>();
    public Task<OpenClawOperationDto<object>> AbortSessionAsync(
        string sessionKey,
        string? runId,
        bool clearQueued,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<object>>();
    public Task<OpenClawOperationDto<object>> PatchSessionModelAsync(
        string sessionKey,
        string model,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<object>>();
    public Task<OpenClawOperationDto<object>> RunCronJobAsync(
        string jobId,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<object>>();
    public Task<OpenClawOperationDto<object>> RunCronJobAsync(
        string jobId,
        string? expectedHash,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<object>>();
    public Task<OpenClawOperationDto<OpenClawCronJobDetailDto>> CreateCronJobAsync(
        CreateOpenClawCronJobRequest request,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<OpenClawCronJobDetailDto>>();
    public Task<OpenClawOperationDto<OpenClawCronJobDetailDto>> PatchCronJobAsync(
        string jobId,
        JsonObject patch,
        string? expectedHash,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<OpenClawCronJobDetailDto>>();
    public Task<OpenClawOperationDto<object>> DeleteCronJobAsync(
        string jobId,
        string? expectedHash = null,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<object>>();
    public Task<OpenClawOperationDto<OpenClawApprovalDto>> ResolveApprovalAsync(
        string approvalId,
        string kind,
        string decision,
        CancellationToken cancellationToken = default,
        OpenClawInvocationContext? invocationContext = null)
        => Unsupported<OpenClawOperationDto<OpenClawApprovalDto>>();

    private static OpenClawAgentDto Agent(
        string id,
        string name,
        string model,
        string workspace)
        => new(
            Id: id,
            Name: name,
            Description: null,
            Model: model,
            Provider: "openai",
            Workspace: workspace,
            Status: "ready");

    private static OpenClawCollectionDto<T> Collection<T>(IReadOnlyList<T> items)
        => new(
            State: "ready",
            Items: items,
            NextCursor: null,
            Message: null,
            Recovery: null,
            CheckedAt: DateTimeOffset.UtcNow);

    private static Task<T> Unsupported<T>()
        => Task.FromException<T>(new NotSupportedException(
            "This test double only supports live agent and session inventory."));
}
