unit frm_CalidadDocumentosList;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.Grids,
  Vcl.DBGrids, Data.DB, Vcl.Buttons, frm_BaseList, uAppTheme, FireDAC.Comp.Client,
  dmg_Main, dmg_Calidad, Vcl.ComCtrls, Winapi.ShellAPI;

type
  TfrmCalidadDocumentosList = class(TfrmBaseList)
    cboFiltroGrupo: TComboBox;
    lblFiltroGrupo: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure btnRefreshClick(Sender: TObject); override;
    procedure btnNewClick(Sender: TObject); override;
    procedure btnEditClick(Sender: TObject); override;
    procedure btnDeleteClick(Sender: TObject); override;
    procedure btnPrintClick(Sender: TObject); override;
    procedure btnGruposClick(Sender: TObject);
    procedure btnPuntosControlClick(Sender: TObject);
    procedure cboFiltroGrupoChange(Sender: TObject);
    procedure dbGridMainTitleClick(Column: TColumn);
  private
    { Private declarations }
    procedure CargarCombos;
    procedure AplicarFiltroDocumentos;
    procedure ConfigurarColumnasGrid;
    procedure SanitizarCampoNombreDocGetText(Sender: TField; var Text: string; DisplayText: Boolean);
  public
    { Public declarations }
  end;

var
  frmCalidadDocumentosList: TfrmCalidadDocumentosList;

implementation

{$R *.dfm}

uses frm_CalidadDocumentoEditor, frm_CalidadGrupos, frm_CalidadPlannerList;

procedure TfrmCalidadDocumentosList.FormCreate(Sender: TObject);
begin
  inherited;
  if not Assigned(dmgCalidad) then
    Application.CreateForm(TdmgCalidad, dmgCalidad);
  dsMain.DataSet := dmgCalidad.qryDocumentos;
  btnPrint.OnClick := btnPrintClick;
end;

procedure TfrmCalidadDocumentosList.FormShow(Sender: TObject);
begin
  inherited;
  pnlSearch.Visible := True;
  pnlLeftFilter.Visible := True;
  lblSearch.Caption := 'Buscar Documento:';
  
  // Garantizar que dsMain apunte a qryDocumentos tras la inicialización del ancestro
  dsMain.DataSet := dmgCalidad.qryDocumentos;

  // Vincular explícitamente el manejador de impresión personalizado para anular el diálogo genérico base
  btnPrint.OnClick := btnPrintClick;
  
  CargarCombos;
  AplicarFiltroDocumentos;
end;

procedure TfrmCalidadDocumentosList.btnRefreshClick(Sender: TObject);
begin
  AplicarFiltroDocumentos;
end;

procedure TfrmCalidadDocumentosList.CargarCombos;
var
  Q: TFDQuery;
begin
  cboFiltroGrupo.Items.Clear;
  cboFiltroGrupo.Items.AddObject('Todos los Grupos', nil);
  
  Q := dmgCalidad.CargarGrupos;
  Q.First;
  while not Q.Eof do
  begin
    cboFiltroGrupo.Items.AddObject(Q.FieldByName('nombre').AsString, TObject(IntPtr(Q.FieldByName('id').AsInteger)));
    Q.Next;
  end;
  cboFiltroGrupo.ItemIndex := 0;
end;

procedure TfrmCalidadDocumentosList.SanitizarCampoNombreDocGetText(Sender: TField; var Text: string; DisplayText: Boolean);
begin
  Text := Sender.AsString;
  // Limpiar residuos de truncamiento de charset UTF-8 en MySQL
  if Pos('EXPEDICIÓNs y', Text) > 0 then
    Text := StringReplace(Text, 'EXPEDICIÓNs y', 'EXPEDICIÓN', [rfReplaceAll]);
  if Pos('MERCANCÍASULOION', Text) > 0 then
    Text := StringReplace(Text, 'MERCANCÍASULOION', 'MERCANCÍAS', [rfReplaceAll]);
  if Pos('MERCANCÍASaje', Text) > 0 then
    Text := StringReplace(Text, 'MERCANCÍASaje', 'MERCANCÍAS', [rfReplaceAll]);
end;

procedure TfrmCalidadDocumentosList.ConfigurarColumnasGrid;
var
  i: Integer;
  Col: TColumn;
begin
  if dbGridMain.Columns.Count = 0 then Exit;

  for i := 0 to dbGridMain.Columns.Count - 1 do
  begin
    Col := dbGridMain.Columns[i];
    if SameText(Col.FieldName, 'codigo_doc') then
    begin
      Col.Title.Caption := 'CÓDIGO';
      Col.Width := 180;
    end
    else if SameText(Col.FieldName, 'nombre_doc') then
    begin
      Col.Title.Caption := 'NOMBRE DEL DOCUMENTO';
      Col.Width := 380;
    end
    else if SameText(Col.FieldName, 'grupo_nombre') then
    begin
      Col.Title.Caption := 'GRUPO DE INFORME';
      Col.Width := 240;
    end
    else if SameText(Col.FieldName, 'periodicidad') then
    begin
      Col.Title.Caption := 'PERIODICIDAD';
      Col.Width := 150;
    end
    else if SameText(Col.FieldName, 'departamento_responsable') then
    begin
      Col.Title.Caption := 'DEPARTAMENTO';
      Col.Width := 200;
    end
    else if SameText(Col.FieldName, 'activo') then
    begin
      Col.Title.Caption := 'ACTIVO';
      Col.Width := 60;
    end;
  end;
end;

procedure TfrmCalidadDocumentosList.AplicarFiltroDocumentos;
var
  LSql: string;
  LGrupoId: Integer;
  LField: TField;
begin
  LGrupoId := 0;
  if (cboFiltroGrupo.ItemIndex > 0) and (cboFiltroGrupo.Items.Objects[cboFiltroGrupo.ItemIndex] <> nil) then
    LGrupoId := Integer(IntPtr(cboFiltroGrupo.Items.Objects[cboFiltroGrupo.ItemIndex]));
    
  dmgCalidad.qryDocumentos.Close;
  LSql := 
    'SELECT d.*, g.nombre AS grupo_nombre ' +
    'FROM ge_calidad_documentos d ' +
    'LEFT JOIN ge_calidad_grupos g ON d.id_grupo = g.id ' +
    'WHERE (d.activo = 1 OR d.activo IS NULL) ';

  if LGrupoId > 0 then
    LSql := LSql + 'AND d.id_grupo = :gid ';

  if Trim(edtSearch.Text) <> '' then
  begin
    LSql := LSql + 'AND (d.codigo_doc LIKE :search OR d.nombre_doc LIKE :search OR g.nombre LIKE :search) ';
  end;

  LSql := LSql + 'ORDER BY g.orden, d.codigo_doc';

  dmgCalidad.qryDocumentos.SQL.Text := LSql;

  if LGrupoId > 0 then
    dmgCalidad.qryDocumentos.ParamByName('gid').AsInteger := LGrupoId;

  if Trim(edtSearch.Text) <> '' then
  begin
    dmgCalidad.qryDocumentos.ParamByName('search').DataType := ftWideString;
    dmgCalidad.qryDocumentos.ParamByName('search').AsWideString := '%' + Trim(edtSearch.Text) + '%';
  end;

  dmgCalidad.qryDocumentos.Open;

  LField := dmgCalidad.qryDocumentos.FindField('nombre_doc');
  if LField <> nil then
    LField.OnGetText := SanitizarCampoNombreDocGetText;

  ConfigurarColumnasGrid;

  // Re-vincular dsMain por seguridad si la superclase lo reinició
  dsMain.DataSet := dmgCalidad.qryDocumentos;
  lblRecordCount.Caption := Format('Registros: %d', [dmgCalidad.qryDocumentos.RecordCount]);
end;

procedure TfrmCalidadDocumentosList.cboFiltroGrupoChange(Sender: TObject);
begin
  AplicarFiltroDocumentos;
end;

procedure TfrmCalidadDocumentosList.dbGridMainTitleClick(Column: TColumn);
var
  LFieldName: string;
begin
  if not Assigned(dsMain.DataSet) or not (dsMain.DataSet is TFDQuery) then Exit;

  LFieldName := Column.FieldName;
  if SameText(LFieldName, 'grupo_nombre') then
    LFieldName := 'id_grupo'
  else if SameText(LFieldName, 'departamento_responsable') then
    LFieldName := 'departamento';

  try
    TFDQuery(dsMain.DataSet).IndexFieldNames := LFieldName;
  except
    // Si la columna es calculada o no indexable directamente
  end;
end;

procedure TfrmCalidadDocumentosList.btnNewClick(Sender: TObject);
var
  LEditor: TfrmCalidadDocumentoEditor;
begin
  LEditor := TfrmCalidadDocumentoEditor.Create(Self);
  try
    LEditor.DocumentoId := 0; // Nuevo Documento
    if LEditor.ShowModal = mrOk then
      AplicarFiltroDocumentos;
  finally
    LEditor.Free;
  end;
end;

procedure TfrmCalidadDocumentosList.btnEditClick(Sender: TObject);
var
  LEditor: TfrmCalidadDocumentoEditor;
  LDocId: Integer;
begin
  if dmgCalidad.qryDocumentos.IsEmpty then Exit;

  LDocId := dmgCalidad.qryDocumentos.FieldByName('id').AsInteger;
  LEditor := TfrmCalidadDocumentoEditor.Create(Self);
  try
    LEditor.DocumentoId := LDocId;
    if LEditor.ShowModal = mrOk then
      AplicarFiltroDocumentos;
  finally
    LEditor.Free;
  end;
end;

procedure TfrmCalidadDocumentosList.btnDeleteClick(Sender: TObject);
var
  LDocId: Integer;
begin
  if dmgCalidad.qryDocumentos.IsEmpty then Exit;

  if MessageDlg('¿Confirma desactivar este documento del catálogo general y eliminar su archivo adjunto?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
  begin
    LDocId := dmgCalidad.qryDocumentos.FieldByName('id').AsInteger;

    // Eliminar físicamente el documento adjunto almacenado en la tabla ge_documentos
    dmgCalidad.qryExecCalidad.Close;
    dmgCalidad.qryExecCalidad.SQL.Text := 'DELETE FROM ge_documentos WHERE id_documento_calidad = :doc_id';
    dmgCalidad.qryExecCalidad.ParamByName('doc_id').AsInteger := LDocId;
    dmgCalidad.qryExecCalidad.ExecSQL;

    dmgCalidad.qryExecCalidad.Close;
    dmgCalidad.qryExecCalidad.SQL.Text := 'UPDATE ge_calidad_documentos SET activo = 0 WHERE id = :id';
    dmgCalidad.qryExecCalidad.ParamByName('id').AsInteger := LDocId;
    dmgCalidad.qryExecCalidad.ExecSQL;
    AplicarFiltroDocumentos;
  end;
end;

procedure TfrmCalidadDocumentosList.btnGruposClick(Sender: TObject);
var
  LGruposForm: TfrmCalidadGrupos;
begin
  LGruposForm := TfrmCalidadGrupos.Create(Self);
  try
    if LGruposForm.ShowModal = mrOk then
    begin
      CargarCombos;
      AplicarFiltroDocumentos;
    end;
  finally
    LGruposForm.Free;
  end;
end;

procedure TfrmCalidadDocumentosList.btnPuntosControlClick(Sender: TObject);
begin
  btnEditClick(Sender);
end;

procedure TfrmCalidadDocumentosList.btnPrintClick(Sender: TObject);
var
  LDocId: Integer;
  QBlob: TFDQuery;
  LNombreAdjunto, LRutaTemp: string;
  LBlobStream: TStream;
  LEditor: TfrmCalidadDocumentoEditor;
  LHasAdjunto: Boolean;
  LRes: Integer;
begin
  if not Assigned(dmgCalidad) or not dmgCalidad.qryDocumentos.Active or dmgCalidad.qryDocumentos.IsEmpty then Exit;

  LDocId := dmgCalidad.qryDocumentos.FieldByName('id').AsInteger;
  LHasAdjunto := False;
  LNombreAdjunto := '';

  // 1. Comprobar si existe documento físico adjunto en ge_documentos
  QBlob := TFDQuery.Create(nil);
  try
    QBlob.Connection := dmgMain.dbConn;
    QBlob.SQL.Text :=
      'SELECT id, nombre_archivo, archivo FROM ge_documentos ' +
      'WHERE id_documento_calidad = :doc_id AND archivo IS NOT NULL ' +
      'ORDER BY id DESC LIMIT 1';
    QBlob.ParamByName('doc_id').AsInteger := LDocId;
    QBlob.Open;

    if not QBlob.IsEmpty and not QBlob.FieldByName('archivo').IsNull then
    begin
      LBlobStream := QBlob.CreateBlobStream(QBlob.FieldByName('archivo'), bmRead);
      try
        if (LBlobStream <> nil) and (LBlobStream.Size > 0) then
        begin
          LHasAdjunto := True;
          LNombreAdjunto := QBlob.FieldByName('nombre_archivo').AsString;
          if Trim(LNombreAdjunto) = '' then
            LNombreAdjunto := Format('Documento_Calidad_%d.pdf', [LDocId]);
        end;
      finally
        LBlobStream.Free;
      end;
    end;
  finally
    QBlob.Free;
  end;

  // 2. Si SÍ existe adjunto, preguntar al usuario
  if LHasAdjunto then
  begin
    LRes := MessageDlg(
      'Este documento de calidad dispone de un archivo físico / plantilla adjunta almacenada en la base de datos.' + sLineBreak + sLineBreak +
      '¿Qué opción de impresión / visualización desea realizar?' + sLineBreak + sLineBreak +
      '  [ Sí ]          -> Imprimir / Abrir Plantilla PDF Almacenada (' + LNombreAdjunto + ')' + sLineBreak +
      '  [ No ]          -> Generar Plantilla HTML Rellenable con Firma Manuscrita' + sLineBreak +
      '  [ Cancelar ] -> Cancelar operación',
      mtConfirmation, [mbYes, mbNo, mbCancel], 0);

    if LRes = mrYes then
    begin
      // Extraer y abrir el documento adjunto almacenado
      QBlob := TFDQuery.Create(nil);
      try
        QBlob.Connection := dmgMain.dbConn;
        QBlob.SQL.Text :=
          'SELECT archivo FROM ge_documentos ' +
          'WHERE id_documento_calidad = :doc_id AND archivo IS NOT NULL ' +
          'ORDER BY id DESC LIMIT 1';
        QBlob.ParamByName('doc_id').AsInteger := LDocId;
        QBlob.Open;

        if not QBlob.IsEmpty and not QBlob.FieldByName('archivo').IsNull then
        begin
          LRutaTemp := IncludeTrailingPathDelimiter(GetHomePath) + LNombreAdjunto;
          LBlobStream := QBlob.CreateBlobStream(QBlob.FieldByName('archivo'), bmRead);
          try
            TMemoryStream(LBlobStream).SaveToFile(LRutaTemp);
          finally
            LBlobStream.Free;
          end;

          ShellExecute(0, 'open', PChar(LRutaTemp), nil, nil, SW_SHOWNORMAL);
        end;
      finally
        QBlob.Free;
      end;
      Exit;
    end;

    if LRes <> mrNo then Exit; // Salir si cancela o cierra
  end;

  // 3. Generar la plantilla HTML rellenable interactiva si no hay adjunto o si eligió No
  LEditor := TfrmCalidadDocumentoEditor.Create(Self);
  try
    LEditor.DocumentoId := LDocId;
    LEditor.GenerarPlantillaImprimibleHTML;
  finally
    LEditor.Free;
  end;
end;

end.
