using System.Text.RegularExpressions;
using Campus_live_rewrite.api.dbs;
using Campus_live_rewrite.api.server;
using Campus_live_rewrite.api.server.Classes.db_class;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace Campus_live_rewrite.Controllers
{
///
/// Admin panel "Room Editor" tab: everything about ONE room in one place -
/// * the platform flags it is shown for,
/// * each subroom: name, player cap, accessibility, sandbox (building allowed), scene,
/// * each subroom's save file (.room blob): download it, upload a new one (published at once), restore an older save,
/// edit the save's notes / version numbers, see whether the file is really on disk,
/// * each subroom's permissions (what Everyone / Host / Moderator / Contributor / Co-owner / Creator may do in it),
/// * moving or copying subrooms between rooms (a whole map into another room, say).
/// A room's blob files live in Data/CDN/RoomBlobs and are served by /cdn/room/ - the game caches them for a year by NAME, so an
/// upload always gets a NEW name (it never overwrites a file players may already hold).
///
public class AdminRoomToolsController : ControllerBase
{
private static readonly Regex SafeBlob = new(@"^[A-Za-z0-9][A-Za-z0-9._-]{0,200}$", RegexOptions.Compiled);
private static ContentResult J(object o, int status = 200) => new() { Content = JsonConvert.SerializeObject(o), ContentType = "application/json", StatusCode = status };
private static string BlobDir => RoomBlobFilter.BlobDirectory;
private static readonly string[] PermissionNames =
{
RoomPermissions.MakerPen, RoomPermissions.SaveInventions, RoomPermissions.SpawnInventions, RoomPermissions.PlayGizmos,
RoomPermissions.ResetButton, RoomPermissions.DeleteAll, RoomPermissions.Invite,
};
private static readonly (int role, string name)[] Roles = { (0, "Everyone"), (10, "Host"), (20, "Moderator"), (25, "Contributor"), (30, "Co-owner"), (255, "Creator") };
private static object FileInfoOf(string? blob)
{
if (string.IsNullOrWhiteSpace(blob) || !SafeBlob.IsMatch(blob)) return new { name = blob, exists = false, size = 0L };
var fi = new FileInfo(Path.Combine(BlobDir, blob));
return new { name = blob, exists = fi.Exists && fi.Length > 0, size = fi.Exists ? fi.Length : 0L };
}
private static object SaveRow(RoomDBClasses.CurrentSave s) => new
{
id = s.SubRoomDataSaveId, file = FileInfoOf(s.DataBlob), description = s.Description ?? "", created = s.CreatedAt,
persistenceVersion = s.PersistenceVersion, omVersion = s.OMVersion, ugcSubVersion = s.UgcSubVersion, savedBy = s.SavedByAccountId,
};
// ---- find rooms ---------------------------------------------------------------------------
[HttpGet("/admin/api/roomtools/find")]
public ContentResult Find(string q = "")
{
var (_, error) = AuthHelper.ValidateTokenDev(HttpContext);
if (error != null) return error;
q = (q ?? "").Trim().TrimStart('^');
if (q.Length == 0) return J(new { success = true, rooms = new object[0] });
var hits = new List();
if (ulong.TryParse(q, out var id)) { var r = RoomDB.GetRoom(id); if (r != null) hits.Add(r); }
foreach (var r in RoomDB.GetAllRoomsIncludingDorms().Where(r => (r.Name ?? "").Contains(q, StringComparison.OrdinalIgnoreCase)).Take(25))
if (!hits.Any(h => h.RoomId == r.RoomId)) hits.Add(r);
return J(new
{
success = true,
rooms = hits.Take(25).Select(r => new
{
id = r.RoomId, name = r.Name, creator = r.CreatorAccountId == 0 ? "" : PlayerDB.GetPlayerNameById(r.CreatorAccountId),
subrooms = r.SubRooms?.Count ?? 0, dorm = r.IsDorm
})
});
}
// ---- one room, everything ------------------------------------------------------------------
[HttpGet("/admin/api/roomtools/room")]
public ContentResult Room(ulong id)
{
var (_, error) = AuthHelper.ValidateTokenDev(HttpContext);
if (error != null) return error;
var r = RoomDB.GetRoom(id);
if (r == null) return J(new { success = false, message = $"No room {id}." });
var defaults = RoomPermissions.Defaults(0);
return J(new
{
success = true,
room = new
{
id = r.RoomId, name = r.Name, creatorId = r.CreatorAccountId,
creator = r.CreatorAccountId == 0 ? "" : PlayerDB.GetPlayerNameById(r.CreatorAccountId),
accessibility = (int)r.Accessibility, maxPlayers = r.MaxPlayers, dorm = r.IsDorm,
supportsScreens = r.SupportsScreens, supportsWalkVR = r.SupportsWalkVR, supportsTeleportVR = r.SupportsTeleportVR,
supportsVRLow = r.SupportsVRLow, supportsQuest2 = r.SupportsQuest2, supportsMobile = r.SupportsMobile, supportsJuniors = r.SupportsJuniors,
roomBlob = FileInfoOf(r.DataBlob),
},
permissionNames = PermissionNames,
roles = Roles.Select(x => new { role = x.role, name = x.name }),
subRooms = (r.SubRooms ?? new()).Select(s =>
{
var merged = RoomPermissions.Merge(RoomPermissions.Defaults(0), s.Permissions);
var cells = new List