﻿unit uConfigEmail;

interface

uses
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf, FireDAC.Stan.Async, FireDAC.DApt, FireDAC.Comp.DataSet, FireDAC.Comp.Client, uFireDacHelper,
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, Data.DB, 
    System.UITypes, Vcl.ExtDlgs, IdCoderMIME, Winapi.ShellAPI,
  SHDocVw, Vcl.OleCtrls, MSHTML, ActiveX;

type
  TfConfigEmail = class(TForm)
    pnlBottom: TPanel;
    btnGuardar: TButton;
    btnCancelar: TButton;
    PageControl: TPageControl;
    tsEmail: TTabSheet;
    tsFirma: TTabSheet;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    edtSmtpHost: TEdit;
    Label2: TLabel;
    edtSmtpPuerto: TEdit;
    chkSmtpSSL: TCheckBox;
    Label3: TLabel;
    edtSmtpUsuario: TEdit;
    Label4: TLabel;
    edtSmtpPassword: TEdit;
    Label5: TLabel;
    edtSmtpNombre: TEdit;
    btnProbar: TButton;
    GroupBox3: TGroupBox;
    Label9: TLabel;
    edtTplEmailAsunto: TEdit;
    Label10: TLabel;
    mmoTplEmailCuerpo: TMemo;
    pnlTop: TPanel;
    Label12: TLabel;
    cboCuentas: TComboBox;
    btnNueva: TButton;
    btnEliminar: TButton;
    edtNombrePerfil: TEdit;
    // Pestaña Firma
    pnlFirmaTop: TPanel;
    btnInsertarImagen: TButton;
    btnVistaPreviaFirma: TButton;
    Label13: TLabel;
    mmoFirmaHTML: TMemo;
    splFirma: TSplitter;
    procedure cboCuentasChange(Sender: TObject);
    procedure btnNuevaClick(Sender: TObject);
    procedure btnEliminarClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnGuardarClick(Sender: TObject);
    procedure btnCancelarClick(Sender: TObject);
    procedure btnProbarClick(Sender: TObject);
    procedure btnInsertarImagenClick(Sender: TObject);
    procedure btnVistaPreviaFirmaClick(Sender: TObject);
    procedure mmoFirmaHTMLChange(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
    wbrFirmaPreview: TWebBrowser;
    qryConfig: TFDQuery;    // Creado en FormCreate, no en DFM
    FActualizandoPreview: Boolean;
    procedure CargarConfiguracion;
    procedure GuardarConfiguracion;
    function ImagenABase64HTML(const RutaImagen: string): string;
    procedure ActualizarPreviewFirma;
  public
    { Public declarations }
  end;

var
  fConfigEmail: TfConfigEmail;

implementation

{$R *.dfm}

uses datos;

// Convierte un fichero de imagen a una etiqueta <img> con datos en base64
function TfConfigEmail.ImagenABase64HTML(const RutaImagen: string): string;
var
  FS: TFileStream;
  B64: string;
  Ext, MimeType: string;
begin
  Result := '';
  if not FileExists(RutaImagen) then Exit;

  Ext := LowerCase(ExtractFileExt(RutaImagen));
  if Ext = '.jpg' then MimeType := 'image/jpeg'
  else if Ext = '.jpeg' then MimeType := 'image/jpeg'
  else if Ext = '.png' then MimeType := 'image/png'
  else if Ext = '.gif' then MimeType := 'image/gif'
  else if Ext = '.bmp' then MimeType := 'image/bmp'
  else if Ext = '.svg' then MimeType := 'image/svg+xml'
  else MimeType := 'image/jpeg';

  FS := TFileStream.Create(RutaImagen, fmOpenRead or fmShareDenyWrite);
  try
    B64 := TIdEncoderMIME.EncodeStream(FS);
  finally
    FS.Free;
  end;

  Result := '<img src="data:' + MimeType + ';base64,' + B64 + '" style="max-width:300px;">';
end;

procedure TfConfigEmail.FormCreate(Sender: TObject);
begin
  // El WebBrowser se creará en FormShow para asegurar que los handles del sistema estén listos
  wbrFirmaPreview := nil;

  // Crear el query de configuración en código (no está en el DFM)
  qryConfig := TFDQuery.Create(Self);
  qryConfig.Connection := DM.DBagrigest;
  CargarConfiguracion;
end;

procedure TfConfigEmail.FormShow(Sender: TObject);
begin
  if Assigned(wbrFirmaPreview) then Exit;

  try
    // Asegurar inicialización COM
    OleInitialize(nil);

    wbrFirmaPreview := TWebBrowser.Create(Self);
    TWinControl(wbrFirmaPreview).Parent := tsFirma;
    wbrFirmaPreview.Align := alClient;
    wbrFirmaPreview.Visible := True;
    
    // Cargar el contenido si ya hay algo en el memo
    if mmoFirmaHTML.Text <> '' then
      ActualizarPreviewFirma;
  except
    on E: Exception do
    begin
      wbrFirmaPreview := nil;
      // Silenciamos el error para que la ventana pueda usarse
    end;
  end;
end;

procedure TfConfigEmail.FormDestroy(Sender: TObject);
begin
  qryConfig.Free;
end;

// Renderiza el HTML del memo en el TWebBrowser sin fichero temporal
procedure TfConfigEmail.ActualizarPreviewFirma;
var
  Doc: IHTMLDocument2;
  HTML: WideString;
  V: OleVariant;
begin
  if FActualizandoPreview then Exit;
  FActualizandoPreview := True;
  try
    HTML := '<!DOCTYPE html><html><head><meta charset="UTF-8">' +
            '<style>body{font-family:Tahoma,sans-serif;font-size:10pt;}</style></head><body>' +
            mmoFirmaHTML.Text + '</body></html>';

    if not Assigned(wbrFirmaPreview) then Exit;
    if not wbrFirmaPreview.HandleAllocated then Exit;
    
    wbrFirmaPreview.Navigate('about:blank');
    // Esperar sin bloquear la UI
    while wbrFirmaPreview.ReadyState < READYSTATE_COMPLETE do
      Application.ProcessMessages;

    Doc := wbrFirmaPreview.Document as IHTMLDocument2;
    if Assigned(Doc) then
    begin
      // Usar VarArray para cargar HTML directamente (compatible con todas las versiones de Delphi)
      V := VarArrayCreate([0, 0], varVariant);
      V[0] := HTML;
      Doc.Write(PSafeArray(TVarData(V).VArray));
      Doc.Close;
    end;
  finally
    FActualizandoPreview := False;
  end;
end;

procedure TfConfigEmail.mmoFirmaHTMLChange(Sender: TObject);
begin
  // Actualizar el preview de forma diferida mientras el usuario escribe
  ActualizarPreviewFirma;
end;

procedure TfConfigEmail.CargarConfiguracion;
var
  SelID: Integer;
begin
  // Listar cuentas si el combo esta vacio
  if cboCuentas.Items.Count = 0 then
  begin
    qryConfig.Close;
    qryConfig.SQL.Text := 'SELECT id, nombre_perfil FROM config_envio ORDER BY id';
    qryConfig.Open;
    while not qryConfig.Eof do
    begin
      cboCuentas.AddItem(qryConfig.FieldByName('nombre_perfil').AsString, TObject(qryConfig.FieldByName('id').AsInteger));
      qryConfig.Next;
    end;
    if cboCuentas.Items.Count > 0 then
      cboCuentas.ItemIndex := 0;
  end;

  if cboCuentas.ItemIndex = -1 then Exit;
  
  SelID := Integer(cboCuentas.Items.Objects[cboCuentas.ItemIndex]);

  qryConfig.Close;
  qryConfig.SQL.Text := 'SELECT * FROM config_envio WHERE id = :id';
  qryConfig.ParamByName('id').AsInteger := SelID;
  qryConfig.Open;

  if not qryConfig.IsEmpty then
  begin
    edtNombrePerfil.Text := qryConfig.FieldByName('nombre_perfil').AsString;
    edtSmtpHost.Text := qryConfig.FieldByName('smtp_host').AsString;
    edtSmtpPuerto.Text := qryConfig.FieldByName('smtp_puerto').AsString;
    chkSmtpSSL.Checked := qryConfig.FieldByName('smtp_ssl').AsInteger = 1;
    edtSmtpUsuario.Text := qryConfig.FieldByName('smtp_usuario').AsString;
    edtSmtpPassword.Text := qryConfig.FieldByName('smtp_password').AsString;
    edtSmtpNombre.Text := qryConfig.FieldByName('smtp_nombre').AsString;
    
    edtTplEmailAsunto.Text := qryConfig.FieldByName('tpl_email_asunto').AsString;
    mmoTplEmailCuerpo.Text := qryConfig.FieldByName('tpl_email_cuerpo').AsString;

    // Cargar firma HTML (campo puede que no exista aun)
    try
      mmoFirmaHTML.Text := qryConfig.FieldByName('firma_html').AsString;
    except
      mmoFirmaHTML.Text := '';
    end;
  end;
  qryConfig.Close;
end;

procedure TfConfigEmail.GuardarConfiguracion;
var
  SelID: Integer;
begin
  SelID := 0;
  if cboCuentas.ItemIndex <> -1 then
    SelID := Integer(cboCuentas.Items.Objects[cboCuentas.ItemIndex]);

  qryConfig.Close;
  qryConfig.SQL.Text := 'SELECT * FROM config_envio WHERE id = :id';
  qryConfig.ParamByName('id').AsInteger := SelID;
  qryConfig.Open;

  if qryConfig.IsEmpty then
  begin
    // Buscamos el ID más alto actual antes de insertar
    with TFDQuery.Create(nil) do
    try
      Connection := DM.DBagrigest;
      SQL.Text := 'SELECT MAX(id) FROM config_envio';
      Open;
      SelID := Fields[0].AsInteger + 1;
      Close;
    finally
      Free;
    end;

    qryConfig.Insert;
    qryConfig.FieldByName('id').AsInteger := SelID;
  end
  else
    qryConfig.Edit;

  qryConfig.FieldByName('nombre_perfil').AsString := edtNombrePerfil.Text;
  qryConfig.FieldByName('smtp_host').AsString := edtSmtpHost.Text;
  qryConfig.FieldByName('smtp_puerto').AsString := edtSmtpPuerto.Text;
  if chkSmtpSSL.Checked then
    qryConfig.FieldByName('smtp_ssl').AsInteger := 1
  else
    qryConfig.FieldByName('smtp_ssl').AsInteger := 0;
    
  qryConfig.FieldByName('smtp_usuario').AsString := edtSmtpUsuario.Text;
  qryConfig.FieldByName('smtp_password').AsString := edtSmtpPassword.Text;
  qryConfig.FieldByName('smtp_nombre').AsString := edtSmtpNombre.Text;

  qryConfig.FieldByName('tpl_email_asunto').AsString := edtTplEmailAsunto.Text;
  qryConfig.FieldByName('tpl_email_cuerpo').AsString := mmoTplEmailCuerpo.Text;

  // Guardar firma HTML
  try
    qryConfig.FieldByName('firma_html').AsString := mmoFirmaHTML.Text;
  except
    // Si el campo aún no existe en la BD, no fallar
  end;

  qryConfig.Post;
  qryConfig.Close;
  
  // Refrescar lista
  cboCuentas.Clear;
  CargarConfiguracion;
end;

procedure TfConfigEmail.btnCancelarClick(Sender: TObject);
begin
  Close;
end;

procedure TfConfigEmail.btnGuardarClick(Sender: TObject);
begin
  GuardarConfiguracion;
  MessageDlg('Configuración guardada correctamente.', mtInformation, [mbOK], 0);
  Close;
end;

// cboWaModoChange ya no existe porque se eliminaron los controles WhatsApp del formulario

procedure TfConfigEmail.btnProbarClick(Sender: TObject);
begin
  MessageDlg('Por implementar: lógica de prueba SMTP.', mtWarning, [mbOK], 0);
end;

procedure TfConfigEmail.cboCuentasChange(Sender: TObject);
begin
  CargarConfiguracion;
end;

procedure TfConfigEmail.btnNuevaClick(Sender: TObject);
begin
  edtNombrePerfil.Text := 'Nueva Cuenta';
  edtSmtpHost.Text := '';
  edtSmtpPuerto.Text := '587';
  chkSmtpSSL.Checked := True;
  edtSmtpUsuario.Text := '';
  edtSmtpPassword.Text := '';
  edtSmtpNombre.Text := '';
  mmoFirmaHTML.Text := '';
  cboCuentas.ItemIndex := -1;
end;

procedure TfConfigEmail.btnEliminarClick(Sender: TObject);
var
  SelID: Integer;
begin
  if cboCuentas.ItemIndex = -1 then Exit;
  if MessageDlg('¿Confirma eliminar esta cuenta?', mtConfirmation, [mbYes, mbNo], 0) = mrNo then Exit;
  
  SelID := Integer(cboCuentas.Items.Objects[cboCuentas.ItemIndex]);
  qryConfig.Close;
  qryConfig.SQL.Text := 'DELETE FROM config_envio WHERE id = :id';
  qryConfig.ParamByName('id').AsInteger := SelID;
  qryConfig.ExecSQL;
  
  cboCuentas.Clear;
  CargarConfiguracion;
end;

procedure TfConfigEmail.btnInsertarImagenClick(Sender: TObject);
var
  dlg: TOpenPictureDialog;
  TagImg: string;
begin
  dlg := TOpenPictureDialog.Create(Self);
  try
    dlg.Filter := 'Imágenes|*.jpg;*.jpeg;*.png;*.gif;*.bmp;*.svg|Todos los ficheros|*.*';
    dlg.Title := 'Seleccionar imagen para la firma';
    if dlg.Execute then
    begin
      TagImg := ImagenABase64HTML(dlg.FileName);
      if TagImg <> '' then
      begin
        // Insertar en la posición actual del cursor en el memo
        mmoFirmaHTML.SelText := TagImg;
        PageControl.ActivePage := tsFirma;
        MessageDlg('Imagen insertada correctamente.' + #13#10 +
          'La imagen está incrustada en el HTML (no necesita fichero externo).', mtInformation, [mbOK], 0);
      end;
    end;
  finally
    dlg.Free;
  end;
end;

procedure TfConfigEmail.btnVistaPreviaFirmaClick(Sender: TObject);
var
  TempPath, HtmlPath: string;
  FS: TFileStream;
  HTMLDoc: AnsiString;
begin
  if Trim(mmoFirmaHTML.Text) = '' then
  begin
    MessageDlg('La firma está vacía. Escribe el HTML de tu firma primero.', mtInformation, [mbOK], 0);
    Exit;
  end;

  TempPath := IncludeTrailingPathDelimiter(GetEnvironmentVariable('TEMP'));
  HtmlPath := TempPath + 'firma_preview_agrigest.html';

  HTMLDoc := AnsiString(
    '<!DOCTYPE html><html><head><meta charset="UTF-8">' +
    '<title>Vista Previa de Firma</title></head><body>' +
    '<h3 style="font-family:sans-serif;color:#555;">Vista Previa de la Firma</h3>' +
    '<hr style="border:none;border-top:1px solid #ccc;">' +
    mmoFirmaHTML.Text +
    '</body></html>');

  FS := TFileStream.Create(HtmlPath, fmCreate);
  try
    FS.WriteBuffer(HTMLDoc[1], Length(HTMLDoc));
  finally
    FS.Free;
  end;

  ShellExecute(0, 'open', PChar(HtmlPath), nil, nil, SW_SHOWNORMAL);
end;

end.
