using EFCDesk.Classes; using FontAwesome.Sharp; using Microsoft.Win32; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Globalization; using System.Linq; using System.Numerics; using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Windows.Forms; namespace EFCDesk.Forms { public partial class FormExpedientes : Form { private class Paginacion { public long _registro; public long _registros; public long _pagina; public long _paginas; public string? _buscarExpediente; } private static SQLiteHelper _sqliteHelper = new SQLiteHelper(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "historico.db")); private long paginacion = 1000; private bool _clickPorCodigo = false; private Paginacion _paginacion = new Paginacion(); private string DominioEFC = Helpers.DominioExpedienteElectronico(); public FormExpedientes() { InitializeComponent(); dgwExpedientes.SelectionChanged += dgwExpedientes_SelectionChanged!; dgwExpedientes.AutoGenerateColumns = true; dgwExpedientes.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); } private async Task CargarVistaExpedientes(long pagina, string buscarExpediente = "*") { // Limpiar la fuente de datos dgwExpedientes.DataSource = null; // 1) Trabajo pesado en segundo plano DataTable? dt = await Task.Run(() => { var listaExpedientes = _sqliteHelper.ObtenerExpedientes(pagina: pagina, tamanioPagina: paginacion, buscarExpediente: buscarExpediente); if (listaExpedientes == null || listaExpedientes.Count == 0) return null; DataTable table = new DataTable(); table.Columns.Add("Expediente", typeof(string)); table.Columns.Add("Ruta", typeof(string)); table.Columns.Add("Estatus", typeof(string)); table.Columns.Add("Fecha Registro", typeof(string)); // TaskId table.Columns.Add("TaskId", typeof(string)); // TaskId // Columna de Acciones con botón FontAwesome var columnaAcciones = new DataGridViewImageColumn { Name = "Acciones", HeaderText = "Acciones", Width = 50, ImageLayout = DataGridViewImageCellLayout.Zoom }; // Columna de acciones table.Columns.Add("Acciones", typeof(Image)); // Crear el icono UNA sola vez Bitmap iconoVer = IconChar.Eye.ToBitmap( IconFont.Auto, 16, Color.Black ); foreach (var exp in listaExpedientes) { var row = table.NewRow(); row["Expediente"] = exp.Expediente; row["Ruta"] = exp.Ruta; row["Estatus"] = exp.Estado; row["Fecha Registro"] = exp.FechaCreacion; row["TaskId"] = exp.TaskId; row["Acciones"] = iconoVer; table.Rows.Add(row); } return table; }); long totalPaginas = await TotalPaginas(edt_BuscarExpediente.Text); // 2) Volver al UI thread para asignar el origen if (dt != null) { // Deshabilitar el redimensionamiento de ALTOS de filas dgwExpedientes.AllowUserToResizeRows = false; dgwExpedientes.DataSource = dt; dgwExpedientes.Columns["Expediente"].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; dgwExpedientes.Columns["Expediente"].Frozen = true; dgwExpedientes.Columns["Expediente"].Width = 100; dgwExpedientes.Columns["Ruta"].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; dgwExpedientes.Columns["Ruta"].Width = 300; dgwExpedientes.Columns["Estatus"].AutoSizeMode = DataGridViewAutoSizeColumnMode.None; dgwExpedientes.Columns["Estatus"].Width = 100; dgwExpedientes.Columns["Fecha Registro"].AutoSizeMode = DataGridViewAutoSizeColumnMode.None; dgwExpedientes.Columns["Fecha Registro"].Width = 180; dgwExpedientes.Columns["Acciones"].Width = 40; dgwExpedientes.Columns["Acciones"].HeaderText = ""; ((DataGridViewImageColumn)dgwExpedientes.Columns["Acciones"]).ImageLayout = DataGridViewImageCellLayout.Zoom; _ = Task.Run(() => { long total = dgwExpedientes.RowCount; _paginacion._registro = 1; _paginacion._registros = total; _paginacion._pagina = pagina; _paginacion._paginas = totalPaginas; _paginacion._buscarExpediente = ((string.IsNullOrEmpty(buscarExpediente) || string.IsNullOrWhiteSpace(buscarExpediente))) ? "*" : buscarExpediente; ActualizarEtiqueta(); }); } else { _paginacion._registro = 0; _paginacion._registros = 0; _paginacion._pagina = 0; _paginacion._paginas = 0; _paginacion._buscarExpediente = "*"; ActualizarEtiqueta(); } } private async Task ConsultarEstadoTareaAsync(string taskId) { try { var apiClient = Globales.ApiClient; //string url = DominioEFC + $"/api/v1/tasks/status/{taskId}/"; return await apiClient.GetStatusTaskAsync(taskId); } catch (Exception ex) { MessageBox.Show($"Error al consultar estado: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return ""; } } private async Task ProcesarRespuestaTareaAsync(string responseJson, string rutaExpediente) { if (string.IsNullOrEmpty(responseJson)) return; var apiClient = Globales.ApiClient; if (!apiClient.IsJson(responseJson)) return; var data = apiClient.TryParseJson>(responseJson); if (data == null) return; // Extraer información string status = data.ContainsKey("status") ? data["status"]?.ToString() ?? "" : ""; bool successful = data.ContainsKey("successful") && Convert.ToBoolean(data["successful"]); int documentsCreated = 0; bool tieneError = true; if (data.ContainsKey("result") && data["result"] is JsonElement resultElement) { var result = JsonSerializer.Deserialize>(resultElement.GetRawText()); if (result != null) { tieneError = result.ContainsKey("tieneError") && Convert.ToBoolean(result["tieneError"]); documentsCreated = result.ContainsKey("documents_created") ? Convert.ToInt32(result["documents_created"]) : 0; } } // Determinar nuevo estado basado en respuesta string nuevoEstado = "Error"; string mensaje = ""; if (successful && !tieneError) { nuevoEstado = "Procesado"; mensaje = $"Tarea completada. Documentos creados: {documentsCreated}"; } else if (status == "PENDING" || status == "STARTED") { nuevoEstado = "Procesando"; mensaje = "Tarea en proceso..."; } else { mensaje = $"Error en tarea: {status}"; } // Actualizar en SQLite _sqliteHelper.ActaulizarStatusCarpeta(rutaExpediente, nuevoEstado); // Mostrar resultado MessageBox.Show(mensaje, "Estado de Tarea", MessageBoxButtons.OK, MessageBoxIcon.Information); // Recargar la grilla para ver el cambio long pagina = _paginacion._pagina; // 'long' no puede ser null, así que no se necesita el operador '??' string buscarExpediente = _paginacion._buscarExpediente ?? "*"; // Si es null, usar "*" if (!(pagina > 0)) { pagina = 1; // Valor predeterminado si 'pagina' no es válido } // await Task.Run(() => CargarVistaExpedientes(pagina: pagina, buscarExpediente: buscarExpediente)); await CargarVistaExpedientes(pagina: pagina, buscarExpediente: buscarExpediente); } private async void FormExpedientes_Shown(object sender, EventArgs e) { edt_Pagina.Text = "1"; await CargarVistaExpedientes(pagina: 1); } private async void BTN_Buscar_Click(object sender, EventArgs e) { string busqueda = edt_BuscarExpediente.Text.Trim(); if (string.IsNullOrEmpty(busqueda)) { busqueda = "*"; } int pag = int.Parse(edt_Pagina.Text); if (_clickPorCodigo) { // fue llamado desde código await CargarVistaExpedientes(buscarExpediente: busqueda, pagina: pag); _clickPorCodigo = false; // reset } else { // fue el usuario await CargarVistaExpedientes(buscarExpediente: busqueda, pagina: 1); } } private async void btn_siguiente_Click(object sender, EventArgs e) { long totalPaginas = await TotalPaginas(edt_BuscarExpediente.Text); long pag = (int.Parse(edt_Pagina.Text) + 1); if (pag > totalPaginas) return; edt_Pagina.Text = pag.ToString(); _clickPorCodigo = true; BTN_Buscar.PerformClick(); } private void btn_anterior_Click(object sender, EventArgs e) { int pag = (int.Parse(edt_Pagina.Text) - 1); if (pag <= 0) { return; } edt_Pagina.Text = pag.ToString(); _clickPorCodigo = true; BTN_Buscar.PerformClick(); } private void btn_inicio_Click(object sender, EventArgs e) { edt_Pagina.Text = "1"; _clickPorCodigo = true; BTN_Buscar.PerformClick(); } private async void btn_ultimo_Click(object sender, EventArgs e) { long totalPaginas = await TotalPaginas(edt_BuscarExpediente.Text); edt_Pagina.Text = totalPaginas.ToString(); _clickPorCodigo = true; BTN_Buscar.PerformClick(); } private async Task TotalPaginas(string busqueda) { long total = 0; if (string.IsNullOrEmpty(busqueda)) { total = await _sqliteHelper.TotalExpedientes("*"); } else if (string.IsNullOrWhiteSpace(busqueda)) { total = await _sqliteHelper.TotalExpedientes("*"); } else { total = await _sqliteHelper.TotalExpedientes(busqueda); } long resto = total % paginacion; long totalPaginas = ((total - resto) / paginacion); if (resto > 0) totalPaginas += 1; return totalPaginas; } private void ActualizarEtiqueta() { // Si el llamado llega desde otro hilo, lo redirigimos al UI if (lblPaginacion.InvokeRequired) { lblPaginacion.BeginInvoke((MethodInvoker)(() => lblPaginacion.Text = $"[Registro {_paginacion._registro.ToString()} de {_paginacion._registros.ToString()}][Página {_paginacion._pagina.ToString()} de {_paginacion._paginas.ToString()}]")); return; } // Ya estamos en el hilo UI lblPaginacion.Text = $"[Registro {_paginacion._registro.ToString()} de {_paginacion._registros.ToString()}][Página {_paginacion._pagina.ToString()} de {_paginacion._paginas.ToString()}]"; } private void dgwExpedientes_SelectionChanged(object sender, EventArgs e) { if (dgwExpedientes.CurrentRow == null) return; int indiceFila = dgwExpedientes.CurrentRow.Index; _paginacion._registro = (indiceFila + 1); ActualizarEtiqueta(); } private void edt_BuscarExpediente_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == (char)Keys.Return) { e.Handled = true; BTN_Buscar.PerformClick(); } } private async void dgwExpedientes_CellClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex < 0) return; var column = dgwExpedientes.Columns[e.ColumnIndex]; if (column.Name == "Acciones") { object? cellValueExp = dgwExpedientes.Rows[e.RowIndex].Cells["Expediente"].Value; object? cellValueTask = dgwExpedientes.Rows[e.RowIndex].Cells["TaskId"].Value; string? expediente = cellValueExp?.ToString(); string? taskId = cellValueTask?.ToString(); if (string.IsNullOrEmpty(taskId)) return; if (string.IsNullOrEmpty(expediente)) return; //// Ejecutar trabajo pesado en segundo plano //var resultado = await Task.Run(() => //{ // // Simulación de proceso pesado // Thread.Sleep(1000); // return $"Procesado expediente {taskId}"; //}); //MessageBox.Show(resultado); string responseJson = await ConsultarEstadoTareaAsync(taskId); await ProcesarRespuestaTareaAsync(responseJson, expediente); } } } }