using System.Security.Claims; using FlatRender.StudioSvc.Application.Services; using FlatRender.StudioSvc.Models.Requests; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace FlatRender.StudioSvc.Controllers; [ApiController] [Route("v1/saved-projects")] [Authorize] public class StudioController(StudioService svc) : ControllerBase { private Guid UserId => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!); private Guid TenantId => Guid.Parse( User.FindFirstValue("tenant_id") ?? "00000000-0000-0000-0000-000000000001"); [HttpGet] public async Task List([FromQuery] SavedProjectListRequest req) => Ok(await svc.ListProjectsAsync(UserId, req)); // Admin: view any user's saved projects ("user videos" viewer). [HttpGet("by-user/{userId:guid}")] [Authorize(Roles = "Admin")] public async Task ListByUser(Guid userId, [FromQuery] SavedProjectListRequest req) => Ok(await svc.ListProjectsAsync(userId, req)); [HttpGet("{id:guid}")] public async Task Get(Guid id) => Ok(await svc.GetProjectAsync(id, UserId)); [HttpPost] public async Task Create([FromBody] CreateSavedProjectRequest req) { var result = await svc.CreateProjectAsync(UserId, TenantId, req); return CreatedAtAction(nameof(Get), new { id = result.Id }, result); } [HttpPatch("{id:guid}")] public async Task Update(Guid id, [FromBody] UpdateSavedProjectRequest req) => Ok(await svc.UpdateProjectAsync(id, UserId, req)); [HttpDelete("{id:guid}")] public async Task Delete(Guid id) { await svc.DeleteProjectAsync(id, UserId); return NoContent(); } /// /// Save all scenes for a project (full atomic replace). /// Called by the studio editor on every save. /// [HttpPut("{id:guid}/scenes")] public async Task SaveScenes(Guid id, [FromBody] List scenes) => Ok(await svc.SaveScenesAsync(id, UserId, scenes)); /// Update individual scene-input values by content key (live studio edits). [HttpPatch("{id:guid}/contents")] public async Task UpdateContents(Guid id, [FromBody] UpdateContentsRequest req) => Ok(new { updated = await svc.UpdateSceneContentsAsync(id, UserId, req.Items ?? new List()) }); /// Update the project's theme colours (accentColor/secondaryColor/ /// backgroundColor/textColor) so the FlexStory render reads the theme picker. [HttpPatch("{id:guid}/shared-colors")] public async Task UpdateColors(Guid id, [FromBody] UpdateColorsRequest req) => Ok(new { updated = await svc.UpdateSharedColorsAsync(id, UserId, req.Items ?? new List()) }); /// Internal endpoint: get project for render service (no user-ownership check). [HttpGet("{id:guid}/render-payload")] [Authorize(Roles = "Service")] public async Task GetRenderPayload(Guid id) => Ok(await svc.GetProjectForRenderAsync(id)); }