unit uConfigEmail;

interface

uses
  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, FireDAC.Comp.Client,
  System.UITypes, Vcl.ExtDlgs, IdCoderMIME, Winapi.ShellAPI,
  SHDocVw, Vcl.OleCtrls, MSHTML, Winapi.ActiveX;

type
  TEmailProfileItem = class
  public
    Id: string;
    NombrePerfil: string;
    constructor Create(const AId, ANombre: string);
  end;

  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 }
    destructor Destroy; override;
  end;

var
  fConfigEmail: TfConfigEmail;

implementation

{$R *.dfm}

uses dmg_Main;

{ TEmailProfileItem }

constructor TEmailProfileItem.Create(const AId, ANombre: string);
begin
  Id := AId;
  NombrePerfil := ANombre;
end;

{ TfConfigEmail }

destructor TfConfigEmail.Destroy;
var
  Idx: Integer;
begin
  for Idx := 0 to cboCuentas.Items.Count - 1 do
    if cboCuentas.Items.Objects[Idx] <> nil then
      cboCuentas.Items.Objects[Idx].Free;
  inherited Destroy;
end;

// 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
  wbrFirmaPreview := nil;

  // Crear el query de configuración en código
  qryConfig := TFDQuery.Create(Self);
  qryConfig.Connection := dmgMain.dbConn;
  CargarConfiguracion;
end;

procedure TfConfigEmail.FormShow(Sender: TObject);
begin
  if Assigned(wbrFirmaPreview) then Exit;

  try
    OleInitialize(nil);

    wbrFirmaPreview := TWebBrowser.Create(Self);
    TWinControl(wbrFirmaPreview).Parent := tsFirma;
    wbrFirmaPreview.Align := alClient;
    wbrFirmaPreview.Visible := True;
    
    if mmoFirmaHTML.Text <> '' then
      ActualizarPreviewFirma;
  except
    on E: Exception do
    begin
      wbrFirmaPreview := nil;
    end;
  end;
end;

procedure TfConfigEmail.FormDestroy(Sender: TObject);
begin
  qryConfig.Free;
end;

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');
    while wbrFirmaPreview.ReadyState < READYSTATE_COMPLETE do
      Application.ProcessMessages;

    Doc := wbrFirmaPreview.Document as IHTMLDocument2;
    if Assigned(Doc) then
    begin
      V := VarArrayCreate([0, 0], varVariant);
      V[0] := HTML;
      Doc.Write(PSafeArray(TVarData(V).VArray));
      Doc.Close;
    end;
  except
  end;
  FActualizandoPreview := False;
end;

procedure TfConfigEmail.mmoFirmaHTMLChange(Sender: TObject);
begin
  ActualizarPreviewFirma;
end;

procedure TfConfigEmail.CargarConfiguracion;
var
  SelID: string;
  Idx: Integer;
begin
  if cboCuentas.Items.Count = 0 then
  begin
    for Idx := 0 to cboCuentas.Items.Count - 1 do
      if cboCuentas.Items.Objects[Idx] <> nil then
        cboCuentas.Items.Objects[Idx].Free;
    cboCuentas.Items.Clear;

    qryConfig.Close;
    qryConfig.SQL.Text := 'SELECT id, nombre_perfil FROM ge_config_envio ORDER BY nombre_perfil';
    qryConfig.Open;
    while not qryConfig.Eof do
    begin
      cboCuentas.Items.AddObject(qryConfig.FieldByName('nombre_perfil').AsString, 
        TEmailProfileItem.Create(qryConfig.FieldByName('id').AsString, qryConfig.FieldByName('nombre_perfil').AsString));
      qryConfig.Next;
    end;
    if cboCuentas.Items.Count > 0 then
      cboCuentas.ItemIndex := 0;
  end;

  if cboCuentas.ItemIndex = -1 then Exit;
  
  SelID := TEmailProfileItem(cboCuentas.Items.Objects[cboCuentas.ItemIndex]).Id;

  qryConfig.Close;
  qryConfig.SQL.Text := 'SELECT * FROM ge_config_envio WHERE id = :id';
  qryConfig.ParamByName('id').DataType := ftString;
  qryConfig.ParamByName('id').AsString := 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;

    try
      mmoFirmaHTML.Text := qryConfig.FieldByName('firma_html').AsString;
    except
      mmoFirmaHTML.Text := '';
    end;
  end;
  qryConfig.Close;
end;

procedure TfConfigEmail.GuardarConfiguracion;
var
  SelID: string;
  Idx: Integer;
begin
  SelID := '';
  if cboCuentas.ItemIndex <> -1 then
    SelID := TEmailProfileItem(cboCuentas.Items.Objects[cboCuentas.ItemIndex]).Id;

  qryConfig.Close;
  qryConfig.SQL.Text := 'SELECT * FROM ge_config_envio WHERE id = :id';
  qryConfig.ParamByName('id').DataType := ftString;
  qryConfig.ParamByName('id').AsString := SelID;
  qryConfig.Open;

  if qryConfig.IsEmpty then
  begin
    SelID := TGUID.NewGuid.ToString.Replace('{', '').Replace('}', '');
    qryConfig.Insert;
    qryConfig.FieldByName('id').AsString := SelID;
    qryConfig.FieldByName('empresa_id').AsString := dmgMain.CurrentCompanyId;
  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;

  try
    qryConfig.FieldByName('firma_html').AsString := mmoFirmaHTML.Text;
  except
  end;

  qryConfig.Post;
  qryConfig.Close;
  
  for Idx := 0 to cboCuentas.Items.Count - 1 do
    if cboCuentas.Items.Objects[Idx] <> nil then
      cboCuentas.Items.Objects[Idx].Free;
  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;

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: string;
  Idx: Integer;
begin
  if cboCuentas.ItemIndex = -1 then Exit;
  if MessageDlg('¿Confirma eliminar esta cuenta?', mtConfirmation, [mbYes, mbNo], 0) = mrNo then Exit;
  
  SelID := TEmailProfileItem(cboCuentas.Items.Objects[cboCuentas.ItemIndex]).Id;
  qryConfig.Close;
  qryConfig.SQL.Text := 'DELETE FROM ge_config_envio WHERE id = :id';
  qryConfig.ParamByName('id').DataType := ftString;
  qryConfig.ParamByName('id').AsString := SelID;
  qryConfig.ExecSQL;
  
  for Idx := 0 to cboCuentas.Items.Count - 1 do
    if cboCuentas.Items.Objects[Idx] <> nil then
      cboCuentas.Items.Objects[Idx].Free;
  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
        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(ExtractFilePath(ParamStr(0)) + 'tmp');
  ForceDirectories(TempPath);
  HtmlPath := TempPath + 'firma_preview_gestion.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;margin:10px 0">' +
    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.
