using line_gestao_api.Data; using line_gestao_api.Dtos; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace line_gestao_api.Controllers { [ApiController] [Route("api/user-data")] public class UserDataController : ControllerBase { private readonly AppDbContext _db; public UserDataController(AppDbContext db) => _db = db; // ========================================================== // GET /api/user-data (LINHAS - Tabela Interna) // ========================================================== [HttpGet] public async Task>> GetAll( [FromQuery] string? search, [FromQuery] string? client, // Filtro por cliente [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.UserDatas.AsNoTracking(); // Filtro exato por cliente (quando abre o card) if (!string.IsNullOrWhiteSpace(client)) { var c = client.Trim(); q = q.Where(x => x.Cliente == c); } // Busca global if (!string.IsNullOrWhiteSpace(search)) { var s = search.Trim(); q = q.Where(x => EF.Functions.ILike(x.Linha ?? "", $"%{s}%") || EF.Functions.ILike(x.Cliente ?? "", $"%{s}%") || EF.Functions.ILike(x.Cpf ?? "", $"%{s}%") || EF.Functions.ILike(x.Email ?? "", $"%{s}%") || EF.Functions.ILike(x.Celular ?? "", $"%{s}%")); } var total = await q.CountAsync(); var sb = (sortBy ?? "item").Trim().ToLowerInvariant(); var desc = string.Equals((sortDir ?? "asc").Trim(), "desc", StringComparison.OrdinalIgnoreCase); q = sb switch { "item" => desc ? q.OrderByDescending(x => x.Item) : q.OrderBy(x => x.Item), "linha" => desc ? q.OrderByDescending(x => x.Linha) : q.OrderBy(x => x.Linha), "cliente" => desc ? q.OrderByDescending(x => x.Cliente) : q.OrderBy(x => x.Cliente), _ => desc ? q.OrderByDescending(x => x.Item) : q.OrderBy(x => x.Item), }; var items = await q .Skip((page - 1) * pageSize) .Take(pageSize) .Select(x => new UserDataListDto { Id = x.Id, Item = x.Item, Linha = x.Linha, Cliente = x.Cliente, Cpf = x.Cpf, Rg = x.Rg, DataNascimento = x.DataNascimento != null ? x.DataNascimento.Value.ToString("yyyy-MM-dd") : null, Email = x.Email, Endereco = x.Endereco, Celular = x.Celular, TelefoneFixo = x.TelefoneFixo }) .ToListAsync(); return Ok(new PagedResult { Page = page, PageSize = pageSize, Total = total, Items = items }); } // ========================================================== // GET /api/user-data/groups (CARDS + KPIs GERAIS) // ========================================================== [HttpGet("groups")] public async Task> GetGroups( [FromQuery] string? search, [FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string? sortBy = "cliente", [FromQuery] string? sortDir = "asc") { page = page < 1 ? 1 : page; pageSize = pageSize < 1 ? 10 : pageSize; var q = _db.UserDatas.AsNoTracking() .Where(x => x.Cliente != null && x.Cliente != ""); if (!string.IsNullOrWhiteSpace(search)) { var s = search.Trim(); q = q.Where(x => EF.Functions.ILike(x.Cliente ?? "", $"%{s}%")); } // ✅ 1. CÁLCULO DOS KPIS GERAIS (Baseado em todos os dados filtrados, sem paginação) var kpis = new UserDataKpisDto { TotalRegistros = await q.CountAsync(), ClientesUnicos = await q.Select(x => x.Cliente).Distinct().CountAsync(), ComCpf = await q.CountAsync(x => x.Cpf != null && x.Cpf != ""), ComEmail = await q.CountAsync(x => x.Email != null && x.Email != "") }; // ✅ 2. AGRUPAMENTO (Para os Cards) var grouped = q .GroupBy(x => x.Cliente!) .Select(g => new UserDataClientGroupDto { Cliente = g.Key, TotalRegistros = g.Count(), ComCpf = g.Count(x => x.Cpf != null && x.Cpf != ""), ComEmail = g.Count(x => x.Email != null && x.Email != "") }); var totalGroups = await grouped.CountAsync(); // Ordenação var desc = string.Equals((sortDir ?? "asc").Trim(), "desc", StringComparison.OrdinalIgnoreCase); grouped = desc ? grouped.OrderByDescending(x => x.Cliente) : grouped.OrderBy(x => x.Cliente); // Paginação dos Grupos var items = await grouped .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); return Ok(new UserDataGroupResponse { Data = new PagedResult { Page = page, PageSize = pageSize, Total = totalGroups, // Total de Clientes Items = items }, Kpis = kpis // KPIs Totais }); } [HttpGet("clients")] public async Task>> GetClients() { return await _db.UserDatas.AsNoTracking() .Where(x => !string.IsNullOrEmpty(x.Cliente)) .Select(x => x.Cliente!) .Distinct() .OrderBy(x => x) .ToListAsync(); } [HttpGet("{id:guid}")] public async Task> GetById(Guid id) { var x = await _db.UserDatas.AsNoTracking().FirstOrDefaultAsync(a => a.Id == id); if (x == null) return NotFound(); return Ok(new UserDataDetailDto { Id = x.Id, Item = x.Item, Linha = x.Linha, Cliente = x.Cliente, Cpf = x.Cpf, Rg = x.Rg, Email = x.Email, Celular = x.Celular, Endereco = x.Endereco, TelefoneFixo = x.TelefoneFixo, DataNascimento = x.DataNascimento }); } } }