using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Nuuru.Server.DTOs.Watch; using Nuuru.Server.Extensions; using Nuuru.Server.Models; using Nuuru.Server.Services; using Nuuru.Server.Services.Search; namespace Nuuru.Server.Controllers { [ApiController] [Route("api/watches")] public class WatchController : ControllerBase { private readonly IWatchService _watchService; private readonly IDefaultQueryFilterService _defaultQueryFilterService; private readonly ILogger _logger; public WatchController( IWatchService watchService, IDefaultQueryFilterService defaultQueryFilterService, ILogger logger) { _watchService = watchService; _defaultQueryFilterService = defaultQueryFilterService; _logger = logger; } [HttpPost("toggle")] [Authorize] public async Task ToggleWatch([FromBody] ToggleWatchRequest request) { try { var userId = User.GetUserId(); if (userId == null) return Unauthorized(new { error = "User ID not found in token" }); if (!TryParseTargetType(request.TargetType, out var targetType)) return BadRequest(new { error = "Invalid target type. Use 'booru_post' or 'forum_thread'." }); if (targetType == WatchTargetType.BooruPost && !await _defaultQueryFilterService.IsPostVisibleAsync(request.TargetId)) { return NotFound(new { error = "Post not found" }); } var isWatching = await _watchService.ToggleWatchAsync(userId.Value, targetType, request.TargetId); var watchCount = await _watchService.GetWatchCountAsync(targetType, request.TargetId); return Ok(new WatchResponse { IsWatching = isWatching, WatchCount = watchCount }); } catch (Exception ex) { _logger.LogError(ex, "Error toggling watch"); return StatusCode(500, new { error = "Failed to toggle watch" }); } } [HttpGet("status")] [Authorize] public async Task GetWatchStatus([FromQuery] string targetType, [FromQuery] int targetId) { try { var userId = User.GetUserId(); if (userId == null) return Unauthorized(new { error = "User ID not found in token" }); if (!TryParseTargetType(targetType, out var parsedType)) return BadRequest(new { error = "Invalid target type. Use 'booru_post' or 'forum_thread'." }); if (parsedType == WatchTargetType.BooruPost && !await _defaultQueryFilterService.IsPostVisibleAsync(targetId)) { return NotFound(new { error = "Post not found" }); } var isWatching = await _watchService.IsWatchingAsync(userId.Value, parsedType, targetId); var watchCount = await _watchService.GetWatchCountAsync(parsedType, targetId); return Ok(new WatchResponse { IsWatching = isWatching, WatchCount = watchCount }); } catch (Exception ex) { _logger.LogError(ex, "Error getting watch status"); return StatusCode(500, new { error = "Failed to get watch status" }); } } private static bool TryParseTargetType(string value, out WatchTargetType targetType) { targetType = default; switch (value?.ToLowerInvariant()) { case "booru_post": targetType = WatchTargetType.BooruPost; return true; case "forum_thread": targetType = WatchTargetType.ForumThread; return true; default: return false; } } } }