using line_gestao_api.Data; using line_gestao_api.Dtos; using line_gestao_api.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Globalization; using System.Text; namespace line_gestao_api.Controllers { [ApiController] [Route("api/chips-virgens")] [Authorize] public class ChipsVirgensController : ControllerBase { private readonly AppDbContext _db; public ChipsVirgensController(AppDbContext db) { _db = db; } [HttpGet] public async Task>> GetAll( [FromQuery] string? search, [FromQuery] int page = 1, [FromQuery] int pageSize = 20, [FromQuery] string? sortBy = "item", [FromQuery] string? sortDir = "asc") { page = page < 1 ? 1 : page; pageSize = pageSize < 1 ? 20 : pageSize; var q = _db.ChipVirgemLines.AsNoTracking(); if (!string.IsNullOrWhiteSpace(search)) { var s = search.Trim(); var hasDateSearch = TryParseSearchDateUtcStart(s, out var searchDateStartUtc); var searchDateEndUtc = hasDateSearch ? searchDateStartUtc.AddDays(1) : DateTime.MinValue; q = q.Where(x => EF.Functions.ILike(x.NumeroDoChip ?? "", $"%{s}%") || EF.Functions.ILike(x.Observacoes ?? "", $"%{s}%") || EF.Functions.ILike(x.Item.ToString(), $"%{s}%") || (hasDateSearch && ((x.CreatedAt >= searchDateStartUtc && x.CreatedAt < searchDateEndUtc) || (x.UpdatedAt >= searchDateStartUtc && x.UpdatedAt < searchDateEndUtc)))); } var total = await q.CountAsync(); var sb = (sortBy ?? "item").Trim().ToLowerInvariant(); var desc = string.Equals((sortDir ?? "asc").Trim(), "desc", StringComparison.OrdinalIgnoreCase); q = sb switch { "numerodochip" => desc ? q.OrderByDescending(x => x.NumeroDoChip ?? "").ThenBy(x => x.Item) : q.OrderBy(x => x.NumeroDoChip ?? "").ThenBy(x => x.Item), "observacoes" => desc ? q.OrderByDescending(x => x.Observacoes ?? "").ThenBy(x => x.Item) : q.OrderBy(x => x.Observacoes ?? "").ThenBy(x => x.Item), _ => desc ? q.OrderByDescending(x => x.Item) : q.OrderBy(x => x.Item) }; var items = await q .Skip((page - 1) * pageSize) .Take(pageSize) .Select(x => new ChipVirgemListDto { Id = x.Id, Item = x.Item, NumeroDoChip = x.NumeroDoChip, Observacoes = x.Observacoes }) .ToListAsync(); return Ok(new PagedResult { Page = page, PageSize = pageSize, Total = total, Items = items }); } [HttpGet("{id:guid}")] public async Task> GetById(Guid id) { var x = await _db.ChipVirgemLines.AsNoTracking().FirstOrDefaultAsync(a => a.Id == id); if (x == null) return NotFound(); return Ok(ToDetailDto(x)); } [HttpPost] [Authorize(Roles = "admin,gestor")] public async Task> Create([FromBody] CreateChipVirgemDto req) { var now = DateTime.UtcNow; var item = req.Item ?? 0; if (item <= 0) { var maxItem = await _db.ChipVirgemLines.MaxAsync(x => (int?)x.Item) ?? 0; item = maxItem + 1; } var e = new ChipVirgemLine { Id = Guid.NewGuid(), Item = item, NumeroDoChip = NullIfEmptyDigits(req.NumeroDoChip), Observacoes = string.IsNullOrWhiteSpace(req.Observacoes) ? null : req.Observacoes.Trim(), CreatedAt = now, UpdatedAt = now }; _db.ChipVirgemLines.Add(e); await _db.SaveChangesAsync(); return CreatedAtAction(nameof(GetById), new { id = e.Id }, ToDetailDto(e)); } [HttpPut("{id:guid}")] [Authorize(Roles = "admin")] public async Task Update(Guid id, [FromBody] UpdateChipVirgemRequest req) { var x = await _db.ChipVirgemLines.FirstOrDefaultAsync(a => a.Id == id); if (x == null) return NotFound(); if (req.Item.HasValue) x.Item = req.Item.Value; x.NumeroDoChip = NullIfEmptyDigits(req.NumeroDoChip); x.Observacoes = string.IsNullOrWhiteSpace(req.Observacoes) ? null : req.Observacoes.Trim(); x.UpdatedAt = DateTime.UtcNow; await _db.SaveChangesAsync(); return NoContent(); } [HttpDelete("{id:guid}")] [Authorize(Roles = "admin")] public async Task Delete(Guid id) { var x = await _db.ChipVirgemLines.FirstOrDefaultAsync(a => a.Id == id); if (x == null) return NotFound(); _db.ChipVirgemLines.Remove(x); await _db.SaveChangesAsync(); return NoContent(); } private static ChipVirgemDetailDto ToDetailDto(ChipVirgemLine x) => new() { Id = x.Id, Item = x.Item, NumeroDoChip = x.NumeroDoChip, Observacoes = x.Observacoes, CreatedAt = x.CreatedAt, UpdatedAt = x.UpdatedAt }; private static string? NullIfEmptyDigits(string? s) { var d = OnlyDigits(s); return string.IsNullOrWhiteSpace(d) ? null : d; } private static string OnlyDigits(string? s) { if (string.IsNullOrWhiteSpace(s)) return ""; var sb = new StringBuilder(); foreach (var c in s) { if (char.IsDigit(c)) sb.Append(c); } return sb.ToString(); } private static bool TryParseSearchDateUtcStart(string value, out DateTime utcStart) { utcStart = default; if (string.IsNullOrWhiteSpace(value)) return false; var s = value.Trim(); DateTime parsed; if (DateTime.TryParse(s, new CultureInfo("pt-BR"), DateTimeStyles.None, out parsed) || DateTime.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.None, out parsed)) { utcStart = DateTime.SpecifyKind(parsed.Date, DateTimeKind.Utc); return true; } return false; } } }