using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using RobotNet10.ScriptEngine.Data;
using RobotNet10.ScriptEngine.Shared;
using RobotNet10.Shared;
using System.Security.Claims;
using System.Text.Json;
namespace RobotNet10.ScriptEngine.Hubs;
///
/// SignalR hub for InstanceMission management operations.
///
[Authorize]
public class InstanceMissionHub : Hub
{
private readonly ScriptEngineDbContext _dbContext;
private readonly MissionManager _missionManager;
public InstanceMissionHub(ScriptEngineDbContext dbContext, MissionManager missionManager)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
_missionManager = missionManager ?? throw new ArgumentNullException(nameof(missionManager));
}
///
/// Searches instance missions with pagination and text search.
/// Running missions are prioritized.
///
public async Task> SearchInstanceMissions(SearchRequest request)
{
var query = _dbContext.InstanceMissions.AsQueryable();
// Text search on MissionName
if (!string.IsNullOrWhiteSpace(request.TxtSearch))
{
var searchText = request.TxtSearch.Trim();
query = query.Where(m => m.MissionName.Contains(searchText));
}
// Get total count before pagination
var total = await query.CountAsync();
// Order by: running missions first (Running, Pausing, Resuming), then by CreatedAt descending
var orderedQuery = query
.OrderByDescending(m => m.State == ScriptMissionState.Running ||
m.State == ScriptMissionState.Pausing ||
m.State == ScriptMissionState.Resuming)
.ThenByDescending(m => m.CreatedAt);
// Apply pagination
var items = await orderedQuery
.Skip((request.Page - 1) * request.Size)
.Take(request.Size)
.Select(m => new InstanceMissionDto
{
Id = m.Id,
MissionName = m.MissionName,
Parameters = m.Parameters ?? "{}",
CreatedAt = m.CreatedAt,
State = m.State,
TotalScore = m.TotalScore,
Score = m.Score,
StoppedAt = m.StoppedAt,
Log = m.Log
})
.ToArrayAsync();
return new SearchResult(total, request.Page, request.Size, items);
}
///
/// Gets the log for a specific instance mission.
///
public async Task GetInstanceMissionLog(Guid missionId)
{
var mission = await _dbContext.InstanceMissions.FindAsync([missionId]);
return mission?.Log;
}
///
/// Cancels a running or paused mission.
///
public Task CancelMission(Guid missionId, string reason)
{
var mission = _missionManager.GetMission(missionId);
if (mission == null)
{
return Task.FromResult(new MessageResult(false, "Mission not found"));
}
try
{
if (mission.State != ScriptMissionState.Running &&
mission.State != ScriptMissionState.Paused &&
mission.State != ScriptMissionState.Pausing)
{
return Task.FromResult(new MessageResult(false, $"Mission is in {mission.State} state and cannot be canceled"));
}
mission.Cancel(reason);
return Task.FromResult(new MessageResult(true, $"Mission canceled{(string.IsNullOrWhiteSpace(reason) ? "" : $": {reason}")}"));
}
catch (Exception ex)
{
return Task.FromResult(new MessageResult(false, $"Failed to cancel mission: {ex.Message}"));
}
}
///
/// Pauses a running mission.
///
public Task PauseMission(Guid missionId)
{
var mission = _missionManager.GetMission(missionId);
if (mission == null)
{
return Task.FromResult(new MessageResult(false, "Mission not found"));
}
try
{
if (mission.State != ScriptMissionState.Running)
{
return Task.FromResult(new MessageResult(false, $"Mission is in {mission.State} state and cannot be paused"));
}
mission.Pause();
return Task.FromResult(new MessageResult(true, "Mission paused"));
}
catch (Exception ex)
{
return Task.FromResult(new MessageResult(false, $"Failed to pause mission: {ex.Message}"));
}
}
///
/// Resumes a paused mission.
///
public Task ResumeMission(Guid missionId)
{
var mission = _missionManager.GetMission(missionId);
if (mission == null)
{
return Task.FromResult(new MessageResult(false, "Mission not found"));
}
try
{
if (mission.State != ScriptMissionState.Paused)
{
return Task.FromResult(new MessageResult(false, $"Mission is in {mission.State} state and cannot be resumed"));
}
mission.Resume();
return Task.FromResult(new MessageResult(true, "Mission resumed"));
}
catch (Exception ex)
{
return Task.FromResult(new MessageResult(false, $"Failed to resume mission: {ex.Message}"));
}
}
}