unit View.ComplaintArchive;

interface

uses
  System.SysUtils, System.Classes, JS, Web,
  WEBLib.Graphics, WEBLib.Controls, WEBLib.Forms, WEBLib.Dialogs,
  Vcl.Controls, Vcl.StdCtrls, Data.DB,
  WEBLib.StdCtrls, WEBLib.Grids, WEBLib.DBCtrls, WEBLib.DB,
  XData.Web.Client, XData.Web.JsonDataset, XData.Web.Dataset,
  ConnectionModule;

type
  TFViewComplaintArchive = class(TWebForm)
    tblRemarksArc: TWebDBTableControl;
    xdwcComplaintArchive: TXDataWebClient;
    xdwdsRemarksArc: TXDataWebDataSet;
    xdwdsRemarksArcMemoId: TStringField;
    xdwdsRemarksArcCFSId: TStringField;
    xdwdsRemarksArcMemoType: TStringField;
    xdwdsRemarksArcTimestamp: TStringField;
    xdwdsRemarksArcBadgeNumber: TStringField;
    xdwdsRemarksArcRemarks: TStringField;
    wdsRemarksArc: TWebDataSource;
    btnUntArc: TWebButton;
    btnREMArc: TWebButton;
    btnE911Arc: TWebButton;
    btnCmpArc: TWebButton;
    procedure btnCmpArcClick(Sender: TObject);
    procedure btnE911ArcClick(Sender: TObject);
    procedure btnREMArcClick(Sender: TObject);
    procedure btnUntArcClick(Sender: TObject);
  private
    FComplaintId: string;
    FCfsId: string;

    FAllMemos: TJSArray;

    FShowCMP: Boolean;
    FShowE911: Boolean;
    FShowREM: Boolean;
    FShowUNT: Boolean;

    FInitialized: Boolean;

    procedure WireUi;
    procedure SetTextById(const Id, Value: string);
    procedure SetHiddenById(const Id: string; Hidden: Boolean);
    procedure SetButtonActive(aButton: TWebButton; Active: Boolean);

    [async] procedure LoadArchiveAsync;
    [async] procedure LoadMemosAsync;

    procedure ApplyMemoFilters;

    function GetMemoTypeCode(const MemoType: string): string;
    function MemoTypeLabel(const MemoType: string): string;

    function MemoTypeInList(const memoType: string; const list: array of string): Boolean;
    procedure SetRemarksData(dataArr: TJSArray);
    function DeriveStatusFromDates(const dateDispatched, dateArrived, dateCleared: string): string;
  public
  class function CreateForm(const AHostId, AComplaintId: string): TWebForm;
    procedure InitializeForm;
  end;

implementation

uses
  View.Main;

{$R *.dfm}

class function TFViewComplaintArchive.CreateForm(const AHostId, AComplaintId: string): TWebForm;

  procedure AfterCreate(AForm: TObject);
  begin
    with TFViewComplaintArchive(AForm) do
    begin
      FComplaintId := AComplaintId;
      InitializeForm;
    end;
  end;

begin
  Application.CreateForm(TFViewComplaintArchive, AHostId, Result, @AfterCreate);
end;


procedure TFViewComplaintArchive.InitializeForm;
begin
  if FInitialized then
    Exit;

  FInitialized := True;

  xdwcComplaintArchive.Connection := DMConnection.ApiConnection;
  xdwdsRemarksArc.Connection := DMConnection.ApiConnection;

  FAllMemos := nil;

  FShowCMP := True;
  FShowE911 := True;
  FShowREM := True;
  FShowUNT := True;

  WireUi;
  LoadArchiveAsync;
end;

procedure TFViewComplaintArchive.WireUi;
begin
  // Nothing required here beyond component OnClick handlers;
  // all element IDs are bound via the DFM.
end;

procedure TFViewComplaintArchive.SetTextById(const Id, Value: string);
var
  el: TJSElement;
begin
  el := Document.getElementById(Id);
  if el <> nil then
    el.innerHTML := Value;
end;

procedure TFViewComplaintArchive.SetHiddenById(const Id: string; Hidden: Boolean);
var
  el: TJSHTMLElement;
begin
  el := TJSHTMLElement(Document.getElementById(Id));
  if el = nil then
    Exit;

  if Hidden then
    el.classList.add('d-none')
  else
    el.classList.remove('d-none');
end;

procedure TFViewComplaintArchive.SetButtonActive(aButton: TWebButton; Active: Boolean);
var
  el: TJSHTMLElement;
begin
  if (aButton = nil) or (aButton.ElementHandle = nil) then
    Exit;

  el := TJSHTMLElement(aButton.ElementHandle);

  if Active then
  begin
    el.classList.add('active');
    el.setAttribute('aria-pressed', 'true');
  end
  else
  begin
    el.classList.remove('active');
    el.setAttribute('aria-pressed', 'false');
  end;
end;

[async] procedure TFViewComplaintArchive.LoadArchiveAsync;
var
  resp: TXDataClientResponse;
  rootObj: TJSObject;
  dataObj: TJSObject;
  business: string;
  dateDispatchedText: string;
  dateArrivedText: string;
  dateClearedText: string;
  statusText: string;
begin
  resp := await(xdwcComplaintArchive.RawInvokeAsync('IApiService.GetComplaintArchiveDetails', [FComplaintId]));
  rootObj := TJSObject(resp.Result);
  dataObj := TJSObject(rootObj['data']);

  SetTextById('lbl_summary_title_arc', 'Summary for Complaint ' + string(dataObj['Complaint']));

  SetTextById('lbl_priority_arc', string(dataObj['Priority']));
  SetTextById('lbl_dispatch_code_arc', string(dataObj['DispatchCodeDesc']));
  SetTextById('lbl_dispatch_district_arc', string(dataObj['DispatchDistrict']));
  SetTextById('lbl_address_arc', string(dataObj['Address']));

  business := '';
  if dataObj.hasOwnProperty('Business') then
    business := string(dataObj['Business']);

  if Trim(business) <> '' then
  begin
    SetTextById('lbl_business_arc', business);
    SetHiddenById('row_business_arc', False);
  end
  else
    SetHiddenById('row_business_arc', True);

  dateDispatchedText := '';
  dateArrivedText := '';
  dateClearedText := '';

  if dataObj.hasOwnProperty('DateDispatched') then
    dateDispatchedText := string(dataObj['DateDispatched']);

  if dataObj.hasOwnProperty('DateArrived') then
    dateArrivedText := string(dataObj['DateArrived']);

  if dataObj.hasOwnProperty('DateCleared') then
    dateClearedText := string(dataObj['DateCleared']);

  statusText := '';
  if dataObj.hasOwnProperty('Status') then
    statusText := string(dataObj['Status']);

  if Trim(statusText) = '' then
    statusText := DeriveStatusFromDates(dateDispatchedText, dateArrivedText, dateClearedText);

  SetTextById('lbl_status_arc', statusText);

  FCfsId := '';
  if dataObj.hasOwnProperty('CFSId') then
    FCfsId := string(dataObj['CFSId']);

  await(LoadMemosAsync);
end;

function TFViewComplaintArchive.MemoTypeLabel(const MemoType: string): string;
var
  code: string;
begin
  code := GetMemoTypeCode(MemoType);

  if code = 'CMP' then
    Exit('CMP');
  if code = 'E911' then
    Exit('E-911');
  if code = 'REM' then
    Exit('REM');
  if code = 'UNT' then
    Exit('UNT');

  Result := MemoType;
end;

function TFViewComplaintArchive.GetMemoTypeCode(const MemoType: string): string;
var
  memoTypeCode: string;
begin
  memoTypeCode := Trim(MemoType);

  if MemoTypeInList(memoTypeCode, ['30', '31', '32', '33', '34']) then
    Exit('UNT');

  if MemoTypeInList(memoTypeCode, ['3', '4']) then
    Exit('CMP');

  if MemoTypeInList(memoTypeCode, ['2']) then
    Exit('E911');

  if MemoTypeInList(memoTypeCode, ['1']) then
    Exit('REM');

  Result := memoTypeCode;
end;

[async] procedure TFViewComplaintArchive.LoadMemosAsync;
var
  resp: TXDataClientResponse;
  rootObj: TJSObject;
  dataArr: TJSArray;
  i: Integer;
  memoObj: TJSObject;
  memoType: string;
begin
  // Reset dataset
  xdwdsRemarksArc.Close;

  if Trim(FCfsId) = '' then
    Exit;

  resp := await(xdwcComplaintArchive.RawInvokeAsync('IApiService.GetComplaintMemos', [FCfsId]));
  rootObj := TJSObject(resp.Result);
  dataArr := TJSArray(rootObj['data']);

  // Save master array for filtering
  FAllMemos := dataArr;

  // Add/normalize memo type label/code (client-side)
  for i := 0 to dataArr.length - 1 do
  begin
    memoObj := TJSObject(dataArr[i]);
    memoType := string(memoObj['MemoType']);
    memoObj['MemoTypeCode'] := GetMemoTypeCode(memoType);
    memoObj['MemoType'] := MemoTypeLabel(memoType);
  end;

  ApplyMemoFilters;
end;

procedure TFViewComplaintArchive.ApplyMemoFilters;
var
  filtered: TJSArray;
  i: Integer;
  memoObj: TJSObject;
  code: string;
  ok: Boolean;
begin
  if FAllMemos = nil then
    Exit;

  filtered := TJSArray.new;

  for i := 0 to FAllMemos.length - 1 do
  begin
    memoObj := TJSObject(FAllMemos[i]);
    code := string(memoObj['MemoTypeCode']);

    ok := False;
    if (code = 'CMP') and FShowCMP then ok := True;
    if (code = 'E911') and FShowE911 then ok := True;
    if (code = 'REM') and FShowREM then ok := True;
    if (code = 'UNT') and FShowUNT then ok := True;

    if ok then
      filtered.push(memoObj);
  end;

  SetRemarksData(filtered);
end;

procedure TFViewComplaintArchive.btnCmpArcClick(Sender: TObject);
begin
  FShowCMP := not FShowCMP;
  SetButtonActive(btnCmpArc, FShowCMP);
  ApplyMemoFilters;
end;

procedure TFViewComplaintArchive.btnE911ArcClick(Sender: TObject);
begin
  FShowE911 := not FShowE911;
  SetButtonActive(btnE911Arc, FShowE911);
  ApplyMemoFilters;
end;

procedure TFViewComplaintArchive.btnREMArcClick(Sender: TObject);
begin
  FShowREM := not FShowREM;
  SetButtonActive(btnREMArc, FShowREM);
  ApplyMemoFilters;
end;

procedure TFViewComplaintArchive.btnUntArcClick(Sender: TObject);
begin
  FShowUNT := not FShowUNT;
  SetButtonActive(btnUntArc, FShowUNT);
  ApplyMemoFilters;
end;

function TFViewComplaintArchive.MemoTypeInList(const memoType: string; const list: array of string): Boolean;
var
  i: Integer;
begin
  Result := False;

  for i := Low(list) to High(list) do
  begin
    if memoType = list[i] then
      Exit(True);
  end;
end;

procedure TFViewComplaintArchive.SetRemarksData(dataArr: TJSArray);
begin
  xdwdsRemarksArc.Close;
  xdwdsRemarksArc.SetJsonData(dataArr);
  xdwdsRemarksArc.Open;
end;

function TFViewComplaintArchive.DeriveStatusFromDates(const dateDispatched, dateArrived, dateCleared: string): string;
begin
  if Trim(dateCleared) <> '' then
    Exit('Cleared');
  if Trim(dateArrived) <> '' then
    Exit('On Scene');
  if Trim(dateDispatched) <> '' then
    Exit('Dispatched');

  Result := 'Pending';
end;

end.
