unit ConnectionModule;

interface

uses
  System.SysUtils, System.Classes,
  WEBLib.Modules,
  XData.Web.Connection, XData.Web.Client;

type
  TVersionCheckCallback = reference to procedure(success: Boolean; errorMessage: string);

  TDMConnection = class(TWebDataModule)
    ApiConnection: TXDataWebConnection;
    xdwcApi: TXDataWebClient;
    procedure ApiConnectionError(error: TXDataWebConnectionError);
    procedure XDataWebClientError(error: TXDataClientError);
  private
    configLoaded: Boolean;
    versionCheckPending: Boolean;
    pendingCallback: TVersionCheckCallback;

    procedure LoadConfig(loadedProc: TProc<Boolean>);
  public
    const clientVersion = '0.1.0';
    procedure InitApp(readyProc: TProc);
    procedure SetClientConfig(callback: TVersionCheckCallback);
  end;

var
  DMConnection: TDMConnection;

implementation

uses
  JS, Web,
  XData.Web.Request,
  XData.Web.Response;

{$R *.dfm}

procedure TDMConnection.ApiConnectionError(error: TXDataWebConnectionError);
begin
  if versionCheckPending and Assigned(pendingCallback) then
  begin
    versionCheckPending := False;
    pendingCallback(False, 'Unable to reach server to verify version. Please reload.');
    pendingCallback := nil;
  end;
end;

procedure TDMConnection.XDataWebClientError(error: TXDataClientError);
begin
  if versionCheckPending and Assigned(pendingCallback) then
  begin
    versionCheckPending := False;
    pendingCallback(False, 'Unable to verify version. Please reload.');
    pendingCallback := nil;
  end;
end;

procedure TDMConnection.LoadConfig(loadedProc: TProc<Boolean>);

  procedure onSuccess(response: IHttpResponse);
  var
    obj: TJSObject;
    apiUrl: string;
  begin
    apiUrl := '';

    if response.StatusCode = 200 then
    begin
      obj := TJSObject(TJSJSON.parse(response.ContentAsText));
      apiUrl := JS.toString(obj['ApiUrl']);
    end;

    if apiUrl <> '' then
    begin
      ApiConnection.URL := apiUrl;
      configLoaded := True;
      loadedProc(True);
    end
    else
      loadedProc(False);
  end;

  procedure onError;
  begin
    loadedProc(False);
  end;

var
  conn: TXDataWebConnection;
begin
  if configLoaded then
  begin
    loadedProc(True);
    Exit;
  end;

  conn := TXDataWebConnection.Create(nil);
  try
    conn.SendRequest(THttpRequest.Create('config/config.json'), @onSuccess, @onError);
  finally
    conn.Free;
  end;
end;

procedure TDMConnection.InitApp(readyProc: TProc);
begin
  if Assigned(readyProc) then
    readyProc;
end;

procedure TDMConnection.SetClientConfig(callback: TVersionCheckCallback);

  procedure configLoadedProc(success: Boolean);
  begin
    if not success then
    begin
      callback(False, 'Missing or invalid config/config.json (ApiUrl).');
      Exit;
    end;

    pendingCallback := callback;
    versionCheckPending := True;

    xdwcApi.Connection := ApiConnection;

    ApiConnection.Open(
      procedure
      begin
        xdwcApi.RawInvoke('IApiService.VerifyVersion', [clientVersion],
          procedure(response: TXDataClientResponse)
          var
            jsonResult: TJSObject;
            errorMsg: string;
          begin
            versionCheckPending := False;

            jsonResult := TJSObject(response.Result);

            if Assigned(jsonResult) and jsonResult.HasOwnProperty('error') then
              errorMsg := string(jsonResult['error'])
            else
              errorMsg := '';

            if errorMsg <> '' then
              pendingCallback(False, errorMsg)
            else
              pendingCallback(True, '');

            pendingCallback := nil;
          end);
      end);
  end;

begin
  LoadConfig(@configLoadedProc);
end;

end.

