using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using DramaLing.Api.Data; using DramaLing.Api.Models.Entities; using Microsoft.AspNetCore.Authorization; using System.Security.Claims; namespace DramaLing.Api.Controllers; [ApiController] [Route("api/[controller]")] [Authorize] public class CardSetsController : ControllerBase { private readonly DramaLingDbContext _context; public CardSetsController(DramaLingDbContext context) { _context = context; } private Guid GetUserId() { var userIdString = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? User.FindFirst("sub")?.Value; if (Guid.TryParse(userIdString, out var userId)) return userId; throw new UnauthorizedAccessException("Invalid user ID"); } [HttpGet] public async Task GetCardSets() { try { var userId = GetUserId(); var cardSets = await _context.CardSets .Where(cs => cs.UserId == userId) .OrderByDescending(cs => cs.CreatedAt) .Select(cs => new { cs.Id, cs.Name, cs.Description, cs.Color, cs.CardCount, cs.CreatedAt, cs.UpdatedAt, // 計算進度 (簡化版) Progress = cs.CardCount > 0 ? _context.Flashcards .Where(f => f.CardSetId == cs.Id) .Average(f => (double?)f.MasteryLevel) ?? 0 : 0, LastStudied = cs.UpdatedAt, Tags = new string[] { } // Phase 1 簡化 }) .ToListAsync(); return Ok(new { Success = true, Data = new { Sets = cardSets } }); } catch (UnauthorizedAccessException) { return Unauthorized(new { Success = false, Error = "Unauthorized" }); } catch (Exception ex) { return StatusCode(500, new { Success = false, Error = "Failed to fetch card sets", Timestamp = DateTime.UtcNow }); } } [HttpPost] public async Task CreateCardSet([FromBody] CreateCardSetRequest request) { try { var userId = GetUserId(); if (string.IsNullOrWhiteSpace(request.Name)) return BadRequest(new { Success = false, Error = "Name is required" }); if (request.Name.Length > 255) return BadRequest(new { Success = false, Error = "Name must be less than 255 characters" }); var cardSet = new CardSet { Id = Guid.NewGuid(), UserId = userId, Name = request.Name.Trim(), Description = request.Description?.Trim(), Color = request.Color ?? "bg-blue-500" }; _context.CardSets.Add(cardSet); await _context.SaveChangesAsync(); return Ok(new { Success = true, Data = cardSet, Message = "Card set created successfully" }); } catch (UnauthorizedAccessException) { return Unauthorized(new { Success = false, Error = "Unauthorized" }); } catch (Exception ex) { return StatusCode(500, new { Success = false, Error = "Failed to create card set", Timestamp = DateTime.UtcNow }); } } [HttpPut("{id}")] public async Task UpdateCardSet(Guid id, [FromBody] UpdateCardSetRequest request) { try { var userId = GetUserId(); var cardSet = await _context.CardSets .FirstOrDefaultAsync(cs => cs.Id == id && cs.UserId == userId); if (cardSet == null) return NotFound(new { Success = false, Error = "Card set not found" }); if (!string.IsNullOrEmpty(request.Name)) cardSet.Name = request.Name.Trim(); if (request.Description != null) cardSet.Description = request.Description?.Trim(); if (!string.IsNullOrEmpty(request.Color)) cardSet.Color = request.Color; cardSet.UpdatedAt = DateTime.UtcNow; await _context.SaveChangesAsync(); return Ok(new { Success = true, Data = cardSet, Message = "Card set updated successfully" }); } catch (UnauthorizedAccessException) { return Unauthorized(new { Success = false, Error = "Unauthorized" }); } catch (Exception ex) { return StatusCode(500, new { Success = false, Error = "Failed to update card set", Timestamp = DateTime.UtcNow }); } } [HttpDelete("{id}")] public async Task DeleteCardSet(Guid id) { try { var userId = GetUserId(); var cardSet = await _context.CardSets .Include(cs => cs.Flashcards) .FirstOrDefaultAsync(cs => cs.Id == id && cs.UserId == userId); if (cardSet == null) return NotFound(new { Success = false, Error = "Card set not found" }); _context.CardSets.Remove(cardSet); await _context.SaveChangesAsync(); return Ok(new { Success = true, Message = "Card set deleted successfully" }); } catch (UnauthorizedAccessException) { return Unauthorized(new { Success = false, Error = "Unauthorized" }); } catch (Exception ex) { return StatusCode(500, new { Success = false, Error = "Failed to delete card set", Timestamp = DateTime.UtcNow }); } } } // Request DTOs public class CreateCardSetRequest { public string Name { get; set; } = string.Empty; public string? Description { get; set; } public string? Color { get; set; } } public class UpdateCardSetRequest { public string? Name { get; set; } public string? Description { get; set; } public string? Color { get; set; } }