unit Api.ServiceImpl;

interface

uses
  XData.Server.Module,
  XData.Service.Common,

  IdSMTP, IdMessage, IdSSLOpenSSL, IdText, IdExplicitTLSClientServerBase, System.NetEncoding,
  IdIOHandlerSocket, IdException, IdSSL, IdSMTPBase, IdGlobal, IdStack, IdWinsock2,
  IdStackConsts, IdIOHandler, IdIOHandlerStack, IdBaseComponent, System.JSON,
  IdComponent, IdTCPConnection, IdTCPClient, IdMessageClient, VCL.Forms, Api.Service;

type
  [ServiceImplementation]
  TApiService = class(TInterfacedObject, IApiService)
  public
    function SendEmail(Name, Email, Subject, Body: string): string;
    function VerifyVersion(ClientVersion: string): TJSONObject;
  end;

implementation

uses
  System.SysUtils,
  System.IniFiles,
  Common.Logging,
  Main;


function TApiService.SendEmail(Name, Email, Subject, Body: string): string;
var
  smtp: TIdSMTP;
  message: TIdMessage;
  confirmMsg: TIdMessage;
  ssl: TIdSSLIOHandlerSocketOpenSSL;
  iniFile: TIniFile;
  iniPath: string;

  fromEmail: string;
  recipientEmail: string;

  safeSenderEmail: string;
  safeSubject: string;
  safeName: string;

  submittedOn: string;
  logPrefix: string;

  htmlBody: string;
  confirmHtml: string;
  bodyHtml: string;

  textPart: TIdText;
  htmlPart: TIdText;
  confirmTextPart: TIdText;
  confirmHtmlPart: TIdText;

  confirmSubject: string;

  bodyLines: TArray<string>;
  i: Integer;
begin
  iniPath := ChangeFileExt(Application.ExeName, '.ini');
  iniFile := TIniFile.Create(iniPath);
  try
    fromEmail := iniFile.ReadString('SMTP', 'EmailWebsiteUses', '');
    recipientEmail := iniFile.ReadString('SMTP', 'RecipientEmail', '');

    safeSenderEmail := Email.Replace(#13, '').Replace(#10, '').Trim;
    safeSubject := Subject.Replace(#13, '').Replace(#10, '').Trim;
    safeName := Name.Trim;

    if SameText(safeSubject, 'Demo Request') then
      logPrefix := '[DEMO]'
    else
      logPrefix := '[CONTACT]';

    Logger.Log(2, logPrefix + ' ----------------------------------------');
    Logger.Log(2, Format('%s SubmittedOn=%s', [logPrefix, FormatDateTime('yyyy-mm-dd HH:nn:ss', Now)]));
    Logger.Log(2, Format('%s Name=%s', [logPrefix, safeName]));
    Logger.Log(2, Format('%s Email=%s', [logPrefix, safeSenderEmail]));
    Logger.Log(2, Format('%s Subject=%s', [logPrefix, safeSubject]));
    Logger.Log(2, logPrefix + ' Body:');

    bodyLines := Body.Replace(#13#10, #10).Replace(#13, #10).Split([#10]);
    for i := 0 to High(bodyLines) do
      Logger.Log(2, logPrefix + ' ' + bodyLines[i]);

    smtp := TIdSMTP.Create(nil);
    message := TIdMessage.Create(nil);
    confirmMsg := TIdMessage.Create(nil);
    ssl := TIdSSLIOHandlerSocketOpenSSL.Create(smtp);
    try
      smtp.IOHandler := ssl;
      smtp.UseTLS := utUseExplicitTLS;
      smtp.AuthType := satDefault;

      smtp.Host := iniFile.ReadString('SMTP', 'Host', '');
      smtp.Port := iniFile.ReadInteger('SMTP', 'Port', 0);
      smtp.Username := iniFile.ReadString('SMTP', 'Username', '');
      smtp.Password := iniFile.ReadString('SMTP', 'Password', '');

      ssl.SSLOptions.Method := sslvTLSv1_2;
      ssl.SSLOptions.SSLVersions := [sslvTLSv1_2];

      submittedOn := FormatDateTime('yyyy-mm-dd hh:nn AM/PM', Now);

      bodyHtml := TNetEncoding.HTML.Encode(Body);
      bodyHtml := bodyHtml.Replace(#13#10, '<br>').Replace(#10, '<br>').Replace(#13, '<br>');

      htmlBody := Format(
        '<html>' +
        '<body style="font-family: Arial, sans-serif; font-size: 14px; color:#222;">' +
          '<h2 style="color: #2E86C1; margin: 0 0 12px 0;">New %s message from EM Systems Website</h2>' +
          '<p style="margin: 0 0 6px 0;"><strong>Submitted On:</strong> %s</p>' +
          '<p style="margin: 0 0 6px 0;"><strong>From:</strong> %s &lt;%s&gt;</p>' +
          '<p style="margin: 0 0 14px 0;"><strong>Subject:</strong> %s</p>' +
          '<hr style="border:0; border-top:1px solid #ddd; margin: 14px 0;">' +
          '<p style="margin: 0 0 8px 0;"><strong>Message:</strong></p>' +
          '<div style="line-height: 1.4;">%s</div>' +
        '</body>' +
        '</html>',
        [
          TNetEncoding.HTML.Encode(safeSubject),
          submittedOn,
          TNetEncoding.HTML.Encode(safeName),
          TNetEncoding.HTML.Encode(safeSenderEmail),
          TNetEncoding.HTML.Encode(safeSubject),
          bodyHtml
        ]
      );

      message.Clear;
      message.From.Address := fromEmail;
      message.Recipients.EmailAddresses := recipientEmail;
      if safeSenderEmail <> '' then
        message.ReplyTo.EmailAddresses := safeSenderEmail;
      message.Subject := safeSubject;

      message.MessageParts.Clear;
      message.ContentType := 'multipart/alternative';

      textPart := TIdText.Create(message.MessageParts, nil);
      textPart.ContentType := 'text/plain; charset=utf-8';
      textPart.Body.Text :=
        'New message from EM Systems Website' + sLineBreak +
        'Submitted On: ' + submittedOn + sLineBreak +
        'From: ' + safeName + ' <' + safeSenderEmail + '>' + sLineBreak +
        'Subject: ' + safeSubject + sLineBreak +
        sLineBreak +
        Body;

      htmlPart := TIdText.Create(message.MessageParts, nil);
      htmlPart.ContentType := 'text/html; charset=utf-8';
      htmlPart.Body.Text := htmlBody;

      smtp.Connect;
      try
        smtp.Send(message);
        Logger.Log(2, Format('%s InternalNotificationSent to=%s', [logPrefix, recipientEmail]));

        if (safeSenderEmail <> '') and (Pos('@', safeSenderEmail) > 1) then
        begin
          if SameText(safeSubject, 'Demo Request') then
            confirmSubject := 'We received your demo request'
          else
            confirmSubject := 'We received your message';

          confirmHtml := Format(
            '<html>' +
            '<body style="font-family: Arial, sans-serif; font-size: 14px; color:#222;">' +
              '<p style="margin:0 0 10px 0;">Hi %s,</p>' +
              '<p style="margin:0 0 10px 0;">Thanks for reaching out. This is a quick confirmation that we received your message.</p>' +
              '<p style="margin:0 0 10px 0;"><strong>Subject:</strong> %s</p>' +
              '<p style="margin:0 0 10px 0;"><strong>Submitted On:</strong> %s</p>' +
              '<p style="margin:0;">We’ll reply as soon as we can.</p>' +
            '</body>' +
            '</html>',
            [
              TNetEncoding.HTML.Encode(safeName),
              TNetEncoding.HTML.Encode(safeSubject),
              submittedOn
            ]
          );

          confirmMsg.Clear;
          confirmMsg.From.Address := fromEmail;
          confirmMsg.Recipients.EmailAddresses := safeSenderEmail;
          confirmMsg.Subject := confirmSubject;

          confirmMsg.ExtraHeaders.Values['Auto-Submitted'] := 'auto-replied';
          confirmMsg.ExtraHeaders.Values['X-Auto-Response-Suppress'] := 'All';

          confirmMsg.MessageParts.Clear;
          confirmMsg.ContentType := 'multipart/alternative';

          confirmTextPart := TIdText.Create(confirmMsg.MessageParts, nil);
          confirmTextPart.ContentType := 'text/plain; charset=utf-8';
          confirmTextPart.Body.Text :=
            'Hi ' + safeName + ',' + sLineBreak +
            sLineBreak +
            'Thanks for reaching out. We have received your message and will be in touch soon.' + sLineBreak +
            sLineBreak +
            '-EM Systems Team';
          confirmHtmlPart := TIdText.Create(confirmMsg.MessageParts, nil);
          confirmHtmlPart.ContentType := 'text/html; charset=utf-8';
          confirmHtmlPart.Body.Text := confirmHtml;

          smtp.Send(confirmMsg);
          Logger.Log(2, Format('%s ConfirmationSent to=%s', [logPrefix, safeSenderEmail]));
        end
        else
          Logger.Log(2, logPrefix + ' ConfirmationSkipped: invalid sender email');
      finally
        smtp.Disconnect;
      end;
    finally
      ssl.Free;
      confirmMsg.Free;
      message.Free;
      smtp.Free;
    end;
  finally
    iniFile.Free;
  end;

  Result := 'Email sent successfully';
end;



function TApiService.VerifyVersion(ClientVersion: string): TJSONObject;
var
  iniFile: TIniFile;
  iniPath: string;
  webClientVersion: string;
  errorMsg: string;
begin
  iniPath := ChangeFileExt(Application.ExeName, '.ini');
  iniFile := TIniFile.Create(iniPath);
  try
    webClientVersion := iniFile.ReadString('Settings', 'webClientVersion', '');
  finally
    iniFile.Free;
  end;

  errorMsg := '';
  if (webClientVersion <> '') and (ClientVersion <> webClientVersion) then
  begin
    Logger.Log(2, Format('VerifyVersion called with mismatch. Server expects %s but client is %s.',
      [webClientVersion, ClientVersion]));

    errorMsg := 'You are running the wrong version of the website, please click the button to update.';
  end;

  Result := TJSONObject.Create;
  Result.AddPair('webClientVersion', webClientVersion);
  if errorMsg <> '' then
    Result.AddPair('error', errorMsg);

  Logger.Log(2, Format('VerifyVersion: client=%s server=%s mismatch=%s',
    [ClientVersion, webClientVersion, BoolToStr(errorMsg <> '', True)]));
end;


initialization
  RegisterServiceType(TApiService);

end.

