unit untAPI;

interface

uses
  Classes, SysUtils, System.Net.HttpClientComponent, System.Net.URLClient,
  System.Net.HttpClient, System.JSON.Serializers;

const
  BASE_URL = 'https://sapi.moecube.com:444';
  API_ACC_SIGNIN = '/accounts/signin';
  API_ACC_AUTHUSER = '/accounts/authUser';
  PUZZLE_URL = 'http://rarnu.xyz:38383/api/mdpro3/puzzle/save';

type
  TCommonResult = class(TPersistent)
  private
    [JsonName('code')]
    FCode: Integer;
    [JsonName('message')]
    FMessage: string;
  published
    property Code: Integer read FCode write FCode;
    property Message: string read FMessage write FMessage;
  end;

  TSavePuzzleResult = class(TCommonResult)
  private
    [JsonName('data')]
    FData: Int64;
  published
    property Data: Int64 read FData write FData;
  end;

type
  TMCSignInReq = class(TPersistent)
  private
    [JsonName('account')]
    FAccount: string;
    [JsonName('password')]
    FPassword: string;
  public
    constructor Create(Acc, Pwd: string);
  published
    property Account: string read FAccount write FAccount;
    property Password: string read FPassword write FPassword;
  end;

type
  TMCUser = class(TPersistent)
  private
    [JsonName('id')]
    FId: Int64;
    [JsonName('username')]
    FUsername: string;
    [JsonName('name')]
    FName: string;
    [JsonName('email')]
    FEmail: string;
    [JsonName('avatar')]
    FAvatar: string;
  published
    property Id: Int64 read FId write FId;
    property Username: string read FUsername write FUsername;
    property Name: string read FName write FName;
    property Email: string read FEmail write FEmail;
    property Avatar: string read FAvatar write FAvatar;
  end;

  TMCUserWithToken = class(TPersistent)
  private
    [JsonName('token')]
    FToken: String;
    [JsonName('user')]
    FUser: TMCUser;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property User: TMCUser read FUser;
    property Token: String read FToken write FToken;
  end;

type
  TEntityPuzzle = class(TPersistent)
  private
    [JsonName('id')]
    FId: Int64;
    [JsonName('contributor')]
    FContributor: string;
    [JsonName('coverCard')]
    FCoverCard: Int64;
    [JsonName('luaScript')]
    FLuaScript: String;
    [JsonName('message')]
    FMessage: string;
    [JsonName('name')]
    FName: string;
    [JsonName('solution')]
    FSolution: string;
    [JsonName('userId')]
    FUserId: Int64;
  published
    property Id: Int64 read FId write FId;
    property Name: string read FName write FName;
    property UserId: Int64 read FUserId write FUserId;
    property Contributor: string read FContributor write FContributor;
    property Message: string read FMessage write FMessage;
    property Solution: string read FSolution write FSolution;
    property CoverCard: Int64 read FCoverCard write FCoverCard;
    property LuaScript: String read FLuaScript write FLuaScript;
  end;

type
  TAPI = class
  public
    class function MCLogin(AAccount: String; APassword: String): TMCUserWithToken;
    class function MCValidate(AToken: String): TMCUser;
    class function SavePuzzle(AP: TEntityPuzzle; AUserId: Int64; AToken: String): TSavePuzzleResult;
  end;

implementation

uses
  untJSON;

{ TAPI }

class function TAPI.MCLogin(AAccount, APassword: String): TMCUserWithToken;
var
  http: TNetHTTPClient;
  url: string;
  signInReq: TMCSignInReq;
  ssReq: TStringStream;
  resp: IHTTPResponse;
  retJson: string;
begin
  Result := nil;
  url := Format('%s%s', [BASE_URL, API_ACC_SIGNIN]);
  http := TNetHTTPClient.Create(nil);
  http.Asynchronous := False;
  http.CustomHeaders['origin'] := 'https://accounts.moecube.com';
  http.CustomHeaders['referer'] := 'https://accounts.moecube.com';
  http.CustomHeaders['sec-fetch-dest'] := 'empty';
  http.CustomHeaders['sec-fetch-mode'] := 'cors';
  http.CustomHeaders['sec-fetch-site'] := 'same-site';
  http.ContentType := 'application/json; charset=UTF-8';

  signInReq:= TMCSignInReq.Create(AAccount, APassword);
  ssReq := TStringStream.Create(TJSON.ObjectToJson<TMCSignInReq>(signInReq), TEncoding.UTF8);
  signInReq.Free;
  try
    resp := http.Post(url, ssReq, nil);
    if resp.StatusCode = 200 then begin
      retJson := resp.ContentAsString(TEncoding.UTF8);
      Result := TJSON.JsonToObject<TMCUserWithToken>(retJson);
    end;
  except

  end;
  ssReq.Free;
  http.Free;
end;

class function TAPI.MCValidate(AToken: String): TMCUser;
var
  http: TNetHTTPClient;
  url: string;
  resp: IHTTPResponse;
  retJson: string;
begin
  Result := nil;
  url := Format('%s%s', [BASE_URL, API_ACC_AUTHUSER]);
  http := TNetHTTPClient.Create(nil);
  http.Asynchronous := False;
  http.CustomHeaders['Authorization'] := Format('Bearer %s', [AToken]);
  try
    resp := http.Get(url);
    if resp.StatusCode = 200 then begin
      retJson := resp.ContentAsString(TEncoding.UTF8);
      Result := TJSON.JsonToObject<TMCUser>(retJson);
    end;
  except

  end;
  http.Free;
end;

class function TAPI.SavePuzzle(AP: TEntityPuzzle; AUserId: Int64; AToken: String): TSavePuzzleResult;
var
  http: TNetHTTPClient;
  url: string;
  ssReq: TStringStream;
  resp: IHTTPResponse;
  retJson: string;
begin
  Result := nil;
  url := PUZZLE_URL;
  http := TNetHTTPClient.Create(nil);
  http.Asynchronous := False;
  http.CustomHeaders['ReqSource'] := 'MDPro3';
  http.CustomHeaders['userId'] := AUserId.ToString();
  http.CustomHeaders['token'] := AToken;
  http.ContentType := 'application/json; charset=UTF-8';
  ssReq := TStringStream.Create(TJSON.ObjectToJson<TEntityPuzzle>(AP), TEncoding.UTF8);
  try
    resp := http.Post(url, ssReq, nil);
    if resp.StatusCode = 200 then begin
      retJson := resp.ContentAsString(TEncoding.UTF8);
      Result := TJSON.JsonToObject<TSavePuzzleResult>(retJson);
    end;
  except

  end;
  ssReq.Free;
  http.Free;
end;

{ TMCSignInReq }

constructor TMCSignInReq.Create(Acc, Pwd: string);
begin
  FAccount := Acc;
  FPassword := Pwd;
end;

{ TMCUserWithToken }

constructor TMCUserWithToken.Create;
begin
  FUser := TMCUser.Create;
end;

destructor TMCUserWithToken.Destroy;
begin
  FUser.Free;
  inherited;
end;

end.
