using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using PlaylistShared.Api.Entities; using PlaylistShared.Api.Extensions; using PlaylistShared.Api.Services; using PlaylistShared.Shared; using PlaylistShared.Shared.DTO; using PlaylistShared.Shared.Shared; using YandexMusic.API.Models.Playlist; [ApiController] [Route("api/[controller]")] public class SharedPlaylistController : ControllerBase { private readonly SharedPlaylistService _sharedService; private readonly YandexMusicService _yandexService; private readonly UserManager _userManager; private readonly TrackAdditionLogService _trackLogService; public SharedPlaylistController( SharedPlaylistService sharedService, YandexMusicService yandexService, UserManager userManager, TrackAdditionLogService trackLogService) { _sharedService = sharedService; _yandexService = yandexService; _userManager = userManager; _trackLogService = trackLogService; } // GET /api/sharedplaylist/{token} [HttpGet("{token}")] public async Task>> GetByToken(string token) { var playlist = await _sharedService.GetByTokenAsync(token); if (playlist == null) return NotFound(ApiResponse.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" })); var currentUserId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; var userIdGuid = !string.IsNullOrEmpty(currentUserId) ? Guid.Parse(currentUserId) : (Guid?)null; // Проверка прав просмотра (требует доступа к сущности) var entity = await _sharedService.GetEntityByTokenAsync(token); if (entity == null || !await _sharedService.CanViewAsync(entity, userIdGuid)) return Unauthorized(ApiResponse.Fail(new ErrorResponse { StatusCode = 401, Message = "Недостаточно прав" })); return Ok(ApiResponse.Ok(playlist)); } // GET /api/sharedplaylist/{token}/tracks [HttpGet("{token}/tracks")] public async Task>> GetTracks(string token) { var currentUserId = User.GetUserIdOrNull(); var playlist = await _sharedService.GetEntityByTokenAsync(token); if (playlist == null) return NotFound(ApiResponse.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" })); if (!await _sharedService.CanViewAsync(playlist, currentUserId)) return Unauthorized(); var creator = await _userManager.FindByIdAsync(playlist.CreatorUserId.ToString()); if (creator == null) return StatusCode(500, ApiResponse.Fail(new ErrorResponse { StatusCode = 500, Message = "Владелец плейлиста не найден" })); var yandexPlaylist = await _yandexService.GetPlaylistAsync(creator, playlist.YandexPlaylistOwnerUid, playlist.YandexPlaylistKind); if (yandexPlaylist == null) return NotFound(ApiResponse.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден в Яндекс.Музыке" })); var dto = MapToYandexPlaylistData(yandexPlaylist); return Ok(ApiResponse.Ok(dto)); } // PUT /api/sharedplaylist/{token}/permissions [HttpPut("{token}/permissions")] [Authorize] public async Task>> UpdatePermissions(string token, [FromBody] UpdatePermissionsDto dto) { var userId = User.GetUserId(); var playlist = await _sharedService.GetEntityByTokenAsync(token); if (playlist == null) return NotFound(ApiResponse.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" })); if (playlist.CreatorUserId != userId) return Forbid(); var updated = await _sharedService.UpdatePermissionsAsync(playlist.Id, dto); if (updated == null) return BadRequest(ApiResponse.Fail(new ErrorResponse { StatusCode = 400, Message = "Ошибка обновления прав" })); return Ok(ApiResponse.Ok(updated)); } // POST /api/sharedplaylist/{token}/add-tracks [HttpPost("{token}/add-tracks")] public async Task>> AddTracks(string token, [FromBody] AddTracksRequest request) { var currentUserId = User.GetUserIdOrNull(); var playlist = await _sharedService.GetEntityByTokenAsync(token); if (playlist == null) return NotFound(ApiResponse.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" })); if (!await _sharedService.CanAddTrackAsync(playlist, currentUserId)) return StatusCode(403, ApiResponse.Fail(new ErrorResponse { StatusCode = 403, Message = "Недостаточно прав для добавления треков" })); var creator = await _userManager.FindByIdAsync(playlist.CreatorUserId.ToString()); if (creator == null) return StatusCode(500, ApiResponse.Fail(new ErrorResponse { StatusCode = 500, Message = "Владелец плейлиста не найден" })); var updatedPlaylist = await _yandexService.AddTracksAsync(creator, playlist.YandexPlaylistOwnerUid, playlist.YandexPlaylistKind, request.TrackIds); if (updatedPlaylist == null) return StatusCode(500, ApiResponse.Fail(new ErrorResponse { StatusCode = 500, Message = "Ошибка при добавлении треков" })); return Ok(ApiResponse.Ok(new { message = "Треки добавлены" })); } // POST /api/sharedplaylist/{token}/remove-tracks [HttpPost("{token}/remove-tracks")] public async Task>> RemoveTracks(string token, [FromBody] RemoveTracksRequest request) { var currentUserId = User.GetUserIdOrNull(); var playlist = await _sharedService.GetEntityByTokenAsync(token); if (playlist == null) return NotFound(ApiResponse.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" })); foreach (var trackId in request.TrackIds) { if (!await _sharedService.CanRemoveTrackAsync(playlist, currentUserId, trackId)) return StatusCode(403, ApiResponse.Fail(new ErrorResponse { StatusCode = 403, Message = $"Недостаточно прав для удаления трека {trackId}" })); } var creator = await _userManager.FindByIdAsync(playlist.CreatorUserId.ToString()); if (creator == null) return StatusCode(500, ApiResponse.Fail(new ErrorResponse { StatusCode = 500, Message = "Владелец плейлиста не найден" })); var updatedPlaylist = await _yandexService.RemoveTracksAsync(creator, playlist.YandexPlaylistOwnerUid, playlist.YandexPlaylistKind, request.TrackIds); if (updatedPlaylist == null) return StatusCode(500, ApiResponse.Fail(new ErrorResponse { StatusCode = 500, Message = "Ошибка при удалении треков" })); foreach (var trackId in request.TrackIds) await _trackLogService.RemoveLogsForTrackAsync(playlist.Id, trackId); return Ok(ApiResponse.Ok(new { message = "Треки удалены" })); } // POST /api/sharedplaylist/{token}/add-track-by-link [HttpPost("{token}/add-track-by-link")] public async Task>> AddTrackByLink(string token, [FromBody] AddTrackByLinkRequest request) { var trackId = ExtractTrackIdFromLink(request.Link); if (string.IsNullOrEmpty(trackId)) return BadRequest(ApiResponse.Fail(new ErrorResponse { StatusCode = 400, Message = "Неверный формат ссылки" })); return await AddTracks(token, new AddTracksRequest { TrackIds = new List { trackId } }); } private string? ExtractTrackIdFromLink(string link) { var match = System.Text.RegularExpressions.Regex.Match(link, @"/track/(\d+)"); return match.Success ? match.Groups[1].Value : null; } private YandexPlaylistData MapToYandexPlaylistData(YPlaylist playlist) { return new YandexPlaylistData { Title = playlist.Title ?? "", Description = playlist.Description ?? "", Tracks = playlist.Tracks?.Select(t => new YandexTrack { Id = t.Track?.Id ?? "", Title = t.Track?.Title ?? "", Artists = t.Track?.Artists?.Select(a => a.Name).ToList() ?? new List(), DurationMs = (int)(t.Track?.DurationMs ?? 0), CoverUri = t.Track?.CoverUri ?? "" }).ToList() ?? new List() }; } }