unit qbAPI;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, AdvUtil, Data.DB, Vcl.Grids, AdvObj,
  BaseGrid, AdvGrid, DBAdvGrid, MemDS, DBAccess, Uni, Vcl.StdCtrls, Vcl.Mask,
  vcl.wwdbedit, vcl.wwdotdot, vcl.wwdbcomb, REST.Client, REST.Types, System.JSON,
  System.Generics.Collections, AdvEdit, vcl.wwdblook, vcl.wwdbdatetimepicker,
  System.Hash, Api.Database, Vcl.ExtCtrls, WEBLib.Forms, WEBLib.Controls, WEBLib.StdCtrls,
  WEBLib.ExtCtrls, WEBLib.REST, WEBLib.WebTools,System.Net.HttpClient,
  System.Net.URLClient, System.Net.HttpClientComponent, System.netencoding,
  IdHTTP, IdSSLOpenSSL, IdSSLOpenSSLHeaders;


type
  TfQB = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
     httpReqTokenRefresh: TWebHttpRequest;
  public
    { Public declarations }
    procedure getCompanyInfo();
    procedure getAccessToken();
    procedure getToken();
    //procedure forceModernTLS();
    procedure ConfigureSSL(IOHandler: TIdSSLIOHandlerSocketOpenSSL);
    //function refreshAccessToken(): boolean;
  end;

var
  fQB: TfQB;

implementation

{$R *.dfm}

procedure TfQB.Button1Click(Sender: TObject);
begin
  //getAccessToken();
  //getCompanyInfo();
  getToken()
end;

procedure TfQB.ConfigureSSL(IOHandler: TIdSSLIOHandlerSocketOpenSSL);
begin
  // For Indy 10.6.2+ (Delphi 10.2 Tokyo+)
  IOHandler.SSLOptions.Method := sslvTLSv1_2;

  // Set SSL versions - maximum compatibility
  IOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2];

  // For very old Indy versions (fallback)
  if not (sslvTLSv1_2 in IOHandler.SSLOptions.SSLVersions) then
  begin
    IOHandler.SSLOptions.Method := sslvSSLv23;
    IOHandler.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
  end;

  IOHandler.SSLOptions.Mode := sslmClient;
end;

procedure TfQB.GetToken;
var
  IdHTTP: TIdHTTP;
  SSLIO: TIdSSLIOHandlerSocketOpenSSL;
  RequestStream: TStringStream;
  EncodedAuth, PostData: string;
begin
  // 1. Encode credentials (same as working Postman request)
  EncodedAuth := 'QUJnTzE0dXZqaDhYcUx1ZDdzcFE4bGtiOThBVXBjZEE3SGJ5TUpmQ0F0bDY1c1E1eXk6YlEwNlRSZW1IZUFHRnpWSFJhVFV2VW9CVTlqcFU5aXRLNk1PTWdxTg==';

  // 2. Prepare POST data (EXACTLY as in Postman)
  PostData := 'grant_type=refresh_token&refresh_token=AB11751554594LX59YtRB69e6vWUjg56d9zCWjOOUisSTd6VfC';

  // 3. Configure HTTP client
  IdHTTP := TIdHTTP.Create(nil);
  SSLIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  try
    // Force TLS 1.2
    SSLIO.SSLOptions.Method := sslvTLSv1_2;
    SSLIO.SSLOptions.SSLVersions := [sslvTLSv1_2];
    IdHTTP.IOHandler := SSLIO;

    // Set headers (EXACT match with Postman)
    IdHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
    IdHTTP.Request.Accept := 'application/json';
    IdHTTP.Request.CustomHeaders.AddValue('Authorization', 'Basic ' + EncodedAuth);

    // 4. Create and send request
    RequestStream := TStringStream.Create(PostData, TEncoding.UTF8);
    try
      Memo1.Lines.Add('Sending request...');
      Memo1.Lines.Add('URL: https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer');
      Memo1.Lines.Add('Headers:');
      Memo1.Lines.Add('Authorization: Basic ' + EncodedAuth);
      Memo1.Lines.Add('Body: ' + PostData);

      // Execute POST
      try
        Memo1.Lines.Add(IdHTTP.Post('https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer', RequestStream));
      except
        on E: EIdHTTPProtocolException do
          Memo1.Lines.Add('Error: ' + E.Message + #13#10 + 'Response: ' + E.ErrorMessage);
      end;
    finally
      RequestStream.Free;
    end;
  finally
    SSLIO.Free;
    IdHTTP.Free;
  end;
end;

procedure TfQB.getAccessToken();
var
  restClient: TRESTClient;
  restRequest: TRESTRequest;
  restResponse: TRESTResponse;
  param: TRESTRequestParameter;
  res: string;
  sid, EncodedAuth, RefreshToken: string;
  jsValue: TJSONValue;
  jsObj, companyInfo: TJSONObject;
  jaCalls: TJSONArray;
  joCall: TJSONObject;
  row: integer;
  i: integer;
  uri, temp, body: string;
  sql: string;
  companyID, client, secret: string;
  pair: TJSONPair;
  item: TRestRequestParameter;
  postBodyStr: string;
begin
  client := 'ABgO14uvjh8XqLud7spQ8lkb98AUpcdA7HbyMJfCAtl65sQ5yy';
  secret := 'bQ06TRemHeAGFzVHRaTUvUoBU9jpU9itK6MOMgqN';
  companyID := '9341454272655710';
  RefreshToken := 'AB11751554594LX59YtRB69e6vWUjg56d9zCWjOOUisSTd6VfC';
  //EncodedAuth := 'QUJnTzE0dXZqaDhYcUx1ZDdzcFE4bGtiOThBVXBjZEE3SGJ5TUpmQ0F0bDY1c1E1eXk6YlEwNlRSZW1IZUFHRnpWSFJhVFV2VW9CVTlqcFU5aXRLNk1PTWdxTg==';
  EncodedAuth := TNetEncoding.Base64.Encode(client + ':' + secret);
  // Prepare the REST client and request
  restClient := TRESTClient.Create(nil);
  restRequest := TRESTRequest.Create(nil);
  restResponse := TRESTResponse.Create(nil);
  restRequest.Client := restClient;
  restRequest.Response := restResponse;

  restClient.BaseURL := 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer';

  // Set request method to POST
  restRequest.Method := rmPOST;

  // Set Content-Type and Accept headers
  restRequest.Params.Clear;

  postBodyStr := 'grant_type=refresh_token&' + #13#10 +
               'refresh_token=' + RefreshToken;

  restRequest.Params.AddHeader('Authorization', 'Basic QUJnTzE0dXZqaDhYcUx1ZDdzcFE4bGtiOThBVXBjZEE3SGJ5TUpmQ0F0bDY1c1E1eXk6YlEwNlRSZW1IZUFHRnpWSFJhVFV2VW9CVTlqcFU5aXRLNk1PTWdxTg==');
  restRequest.Params.AddHeader('Content-Type', 'application/x-www-form-urlencoded');
  restRequest.params.AddHeader('Accept', 'application/json');

  // Set the body with the properly formatted form data
  restRequest.AddBody(postBodyStr, TRESTContentType.ctAPPLICATION_X_WWW_FORM_URLENCODED);

  // Execute the request
  try
    restRequest.Execute;

    // Optionally log the response to the memo for debugging
    Memo1.Lines.Add('Response: ' + restResponse.Content);
  except
    on E: Exception do
      Memo1.Lines.Add('Error: ' + E.Message);
  end;

  // Free resources
  restClient.Free;
  restRequest.Free;
  restResponse.Free;
end;

procedure TfQB.getCompanyInfo();
var
  restClient: TRESTClient;
  restRequest: TRESTRequest;
  restResponse: TRESTResponse;
  param: TRESTRequestParameter;
  res: string;
  sid: string;
  jsValue: TJSONValue;
  jsObj, companyInfo: TJSONObject;
  jaCalls: TJSONArray;
  joCall: TJSONObject;
  row: integer;
  i: integer;
  uri, temp: string;
  sql: string;
  companyID, client, secret: string;
  pair: TJSONPair;
begin
  client := 'ABgO14uvjh8XqLud7spQ8lkb98AUpcdA7HbyMJfCAtl65sQ5yy';
  secret := 'bQ06TRemHeAGFzVHRaTUvUoBU9jpU9itK6MOMgqN';
  companyID := '9341454272655710';
  restClient := TRESTClient.Create(nil);
  restClient.BaseURL := 'https://sandbox-quickbooks.api.intuit.com';

  restRequest := TRESTRequest.Create(nil);
  restRequest.Client := restClient;

  restResponse := TRESTResponse.Create(nil);
  restRequest.Response := restResponse;


  restRequest.Method := rmGET;
  res := '/v3/company/9341454272655710/companyinfo/9341454272655710';
  restRequest.Resource := res;

  param := restRequest.Params.AddItem;
  param.Name := 'Authorization';
  param.Kind := pkHTTPHEADER;
  param.Options := param.Options + [TRESTRequestParameterOption.poDoNotEncode];
  param.Value := 'Bearer eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..jQN6f8KqIOzuz9vUug_-pQ.EmzmjomzD8h1L3jLN2-LnwbeegkYJw2WSqm5FFhXCTBGfaK9Hc16l_NuoKgesfYUNBMFuAO59wgc7bKni6QoCZmA6R40_RuC-fq7aSLms_JHLCvaWe-TiIY0iEDgtCgFP7Bfnw7VAP8QL-A8vkG0wVqFhrjLSbpZWIDMo9n_WG5U_tobHt052YKczM4A-wLtmouLnRNewvjk4YqU36867Z4fOZQ4c2AHm5yhA1CRfYNiKflT4Wv_ERMEG_A1U5FCj_vTs3njbjCrSxooKeW6yJy3pzbAv0eVH_0KFsAi5LjTfyDXPRfVa2XMjtJcfEKnFYvnFw4owOYP8z4TPVB2vNSeYSimHivOWlaWLFQzc1jbGgUpdeMdMqA9Wmpt0JgYZxCSMxDfTmSdYhDOR0ng6osf0qTaeSLsbweYMZRFZTZ1Ob8MNiAhTEPARTrJYgJ3YHdY1G_nX4-LhTJetkduiNzjK_LekBplwy0NnLAujqaiL0D6Wrwc-LNrYgQ4Qc3j46U4jGkOLJ88CIg85pDSAeFtZk5-vL8mRDpZ7s6KX62mIOpzdx_nTTeQgsTDhvUfusQcBshoEw93Tmv5s-tr96pSHXcCq4WLp6bRMsay65cEapQVE4GnZrXoWBwBh0cnpE6DdmXS2GQXXvW6fFsQcq8eTPyLGs-qR6nJL-yybGwI_XTmEsaYzbdT4cFFRRqTstbN_UWnv2BtIYOwgDPcOsBg8CKPa5ZZfJFunkrRI8HDLckgkSoLVMqXKzmMQleu.-tUa8rbIzo9JQylw3T_f1g';

  restRequest.Execute;

  //restresponse.Content
  //jsValue := restResponse.JSONValue;
  jsObj := TJSONObject.ParseJSONValue(restresponse.Content) as TJSONObject;
  companyInfo := TJSONObject(jsObj.GetValue('CompanyInfo'));

  for pair in companyInfo do
  begin
    // Get the value as string
    if pair.JsonValue is TJSONString then
      temp := TJSONString(pair.JsonValue).Value
    else
      temp := pair.JsonValue.ToString; // For non-string values

    // Add the key-value pair to the Memo
    Memo1.Lines.Add(pair.JsonString.Value + ': ' + temp);
  end;

  //temp := companyInfo.Values['CompanyName'].Value;

  //Memo1.Lines.Add(temp);

  i := 1;

  restClient.Free;
  restRequest.Free;
  restResponse.Free;

end;

end.
