// Displays orders in the grid. Allows the user
// to sort the entries, filter their search, and search for a specific person.
// Authors:
// Cameron Hayes
// Mac Stephens

unit View.Orders;

interface

uses
  System.SysUtils, System.Generics.Collections, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
  WEBLib.Forms, WEBLib.Dialogs, WEBLib.Menus, WEBLib.ExtCtrls, WEBLib.StdCtrls,
  WEBLib.JSON, Auth.Service, XData.Web.Client, WebLib.Storage,
  ConnectionModule, App.Types, Vcl.StdCtrls, Vcl.Controls, WEBLib.DBCtrls,
  XData.Web.JsonDataset, WEBLib.DB, Data.DB, XData.Web.Dataset, View.AddOrder,
  WEBLib.Grids;

type
  TFViewOrders = class(TWebForm)
    XDataWebClient1: TXDataWebClient;
    xdwdsOrders: TXDataWebDataSet;
    lblEntries: TWebLabel;
    wcbSortBy: TWebComboBox;
    btnApply: TWebButton;
    edtSearch: TWebEdit;
    wdsOrders: TWebDataSource;
    xdwdsOrderscompanyName: TStringField;
    xdwdsOrdersjobName: TStringField;
    xdwdsOrdersorderDate: TStringField;
    xdwdsOrdersproofDue: TStringField;
    xdwdsOrdersproofDone: TStringField;
    xdwdsOrdersartDue: TStringField;
    xdwdsOrdersartDone: TStringField;
    xdwdsOrdersmountDue: TStringField;
    xdwdsOrdersmountDone: TStringField;
    xdwdsOrdersshipDue: TStringField;
    xdwdsOrdersshipDone: TStringField;
    xdwdsOrdersprice: TStringField;
    xdwdsOrdersID: TStringField;
    xdwdsOrdersqbRefNum: TStringField;
    xdwdsOrderscolors: TStringField;
    btnAddOrder: TWebButton;
    btnFilters: TWebButton;
    dtpStartDate: TWebDateTimePicker;
    dtpEndDate: TWebDateTimePicker;
    xdwdsOrdersplateDue: TStringField;
    xdwdsOrdersplateDone: TStringField;
    xdwdsOrdersorderType: TStringField;
    pnlMessage: TWebPanel;
    lblMessage: TWebLabel;
    btnCloseNotification: TWebButton;
    WebButton1: TWebButton;
    btnPDF: TWebButton;
    wdsCustomers: TWebDataSource;
    xdwdsCustomers: TXDataWebDataSet;
    xdwdsCustomersNAME: TStringField;
    xdwdsCustomersID: TIntegerField;
    xdwdsCustomersCURR_ID: TIntegerField;
    xdwdsSave: TXDataWebDataSet;
    wdsSave: TWebDataSource;
    xdwdsSaveCURR_ID: TIntegerField;
    wdbtcOrders: TWebDBTableControl;
    procedure WebFormCreate(Sender: TObject);
    procedure btnApplyClick(Sender: TObject);
    procedure btnSearchClick(Sender: TObject);
    procedure btnAddOrderClick(Sender: TObject);
    procedure btnFiltersClick(Sender: TObject);
    procedure btnCloseNotificationClick(Sender: TObject);
    procedure WebFormShow(Sender: TObject);
    procedure btnConfirmClick(Sender: TObject);
    procedure btnPDFClick(Sender: TObject);
  private
    FChildForm: TWebForm;
    procedure ClearTable();
    procedure GeneratePagination(TotalPages: Integer);
    function GenerateSearchOptions(): string;
    procedure orderEntry(orderInfo, customerInfo, mode: string);
    procedure HideNotification();
    procedure ShowNotification(Notification: string);
    procedure ShowAddOrderForm();
    [async] procedure Search(searchOptions: string);
    [async] procedure GetOrders(searchOptions: string);
    [async] procedure getUser();
    procedure GeneratePDF(OrderID: string);
    [async] procedure GenerateReportPDF;
    var
      PageNumber: integer;
      PageSize: integer;
      TotalPages: integer;
      StartDate: string;
      EndDate: string;
      OrderBy: string;
      Caller: string;
      filters: boolean;
      info: string;
  public
    class function CreateForm(AElementID, Info: string): TWebForm;

  end;

var
  FViewOrders: TFViewOrders;

implementation

uses
  XData.Model.Classes, View.Main;

{$R *.dfm}

procedure TFViewOrders.btnPDFClick(Sender: TObject);
begin
  GenerateReportPDF;
end;

[async] procedure TFViewOrders.GenerateReportPDF;
var
  searchOptions: string;
begin
  searchOptions := GenerateSearchOptions;

  // Call the server method to generate the PDF
  await(XDataWebClient1.RawInvokeAsync('ILookupService.GenerateReportPDF', [searchOptions]));
  ShowMessage('PDF Report Generated Successfully');
end;


procedure TFViewOrders.WebFormCreate(Sender: TObject);
// Initializes important values:
// PageNumber: What page number the user is on IE 1: 1-10, 2: 11-20 etc
// TotalPages: Total number of pages returned from the search.
// PageSize: Number of entries per page.
var
  today: TDateTime;
begin
  DMConnection.ApiConnection.Connected := True;
  PageNumber := 1;
  TotalPages := 1; // Initial total pages
  wcbSortBy.Text := 'PROOF';
  //today := TDateTime.Today;
  dtpStartDate.Date := 0;
  dtpEndDate.Date := 0;
  getOrders(GenerateSearchOptions());
end;


procedure TFViewOrders.WebFormShow(Sender: TObject);
begin
  console.log(info);
  if info <> '' then
    ShowNotification(info)
  else
    HideNotification();
end;


procedure TFViewOrders.getUser();
var
  xdcResponse: TXDataClientResponse;
  userList, user: TJSObject;
  data: TJSArray;
begin
  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetUsers',
        [JS.toString(AuthService.TokenPayload.Properties['user_name'])]));
  userList :=  TJSObject(xdcResponse.Result);
  data := TJSArray(userList['data']);
  user := TJSObject(data[0]);
end;


class function TFViewOrders.CreateForm(AElementID, Info: string): TWebForm;
var
  localInfo: string;
begin
  localInfo := info;
  Application.CreateForm(TFViewOrders, AElementID, Result,
    procedure(AForm: TObject)
    begin
      with TFViewOrders(AForm) do
      begin
        TFViewOrders(AForm).info := LocalInfo;
      end;
    end
  );
end;


procedure TFViewOrders.ShowAddOrderForm();
var
  newform: TFAddOrder;
begin
  newform := TFAddOrder.CreateNew;

  newform.Caption := 'Select Customer and Order Type';
  newForm.Popup := True;
  newForm.Border := fbDialog;
  console.log(newForm.GetElementHandle);

  // used to manage Back button handling to close subform
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    begin
      if newform.edtID.Text <> '' then
        orderEntry('', newForm.edtID.Text, 'ADD');
    end
  );
end;


procedure TFViewOrders.GeneratePagination(TotalPages: Integer);
// Generates pagination for the table.
// TotalPages: Total amount of pages generated by the search
var
  PaginationElement, PageItem, PageLink: TJSHTMLElement;
  I, Start, Finish: Integer;
begin
  PaginationElement := TJSHTMLElement(document.getElementById('pagination'));
  PaginationElement.innerHTML := ''; // Clear existing pagination

  // Previous Button
  PageItem := TJSHTMLElement(document.createElement('li'));
  PageItem.className := 'page-item';
  if PageNumber = 1 then
    PageItem.classList.add('disabled');
  PageLink := TJSHTMLElement(document.createElement('a'));
  PageLink.className := 'page-link';
  PageLink.innerText := 'Previous';
  PageLink.setAttribute('href', 'javascript:void(0)');
  PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
  begin
    if PageNumber > 1 then
    begin
      Dec(PageNumber);
      GetOrders(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

  // Page Numbers

  if TotalPages <= 7 then
  begin
    for I := 1  to 7 do
    begin
      if I <= TotalPages then
      begin
        PageItem := TJSHTMLElement(document.createElement('li'));
        PageItem.className := 'page-item';
        if I = PageNumber then
          PageItem.classList.add('selected-number'); // Add the selected-number class
        PageLink := TJSHTMLElement(document.createElement('a'));
        PageLink.className := 'page-link';
        PageLink.innerText := IntToStr(I);
        PageLink.setAttribute('href', 'javascript:void(0)');
        PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
        var
          PageNum: Integer;
        begin
          PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
          PageNumber := PageNum;
          GetOrders(GenerateSearchOptions());
        end);
        PageItem.appendChild(PageLink);
        PaginationElement.appendChild(PageItem);
      end;
    end;
  end
  else
  begin
    if PageNumber <= 4 then
    // If page number is low enough no early elipsis needed
    Begin
      Start := 2;
      Finish := 5;
    End
    else if (PageNumber >= (TotalPages - 3)) then
    // If page number is high enough no late elipsis needed
    begin
      Start := TotalPages - 3;
      Finish := TotalPages - 1;
    end
    else
    begin
      Start := PageNumber - 1;
      Finish := PageNumber + 1;
    end;

    PageItem := TJSHTMLElement(document.createElement('li'));
    PageItem.className := 'page-item';
    if 1 = PageNumber then
      PageItem.classList.add('selected-number'); // Add the selected-number class
    PageLink := TJSHTMLElement(document.createElement('a'));
    PageLink.className := 'page-link';
    PageLink.innerText := '1';
    PageLink.setAttribute('href', 'javascript:void(0)');
    PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
    var
      PageNum: Integer;
    begin
      PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
      PageNumber := PageNum;
      GetOrders(GenerateSearchOptions());
    end);
    PageItem.appendChild(PageLink);
    PaginationElement.appendChild(PageItem);

    // Adds Elipse to pagination if page number is too big
    if PageNumber > 4 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      PageItem.classList.add('disabled');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := '...';
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageItem.appendChild(PageLink);
      PaginationElement.appendChild(PageItem);
    end;


    // Adds Page, page - 1, and page + 1 to pagination
    for I := Start  to Finish do
    begin
      if ( I > 1) and (I < TotalPages) then
      begin
        PageItem := TJSHTMLElement(document.createElement('li'));
        PageItem.className := 'page-item';
        if I = PageNumber then
          PageItem.classList.add('selected-number'); // Add the selected-number class
        PageLink := TJSHTMLElement(document.createElement('a'));
        PageLink.className := 'page-link';
        PageLink.innerText := IntToStr(I);
        PageLink.setAttribute('href', 'javascript:void(0)');
        PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
        var
          PageNum: Integer;
        begin
          PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
          PageNumber := PageNum;
          GetOrders(GenerateSearchOptions());
        end);
        PageItem.appendChild(PageLink);
        PaginationElement.appendChild(PageItem);
      end;
    end;

    // adds ellipse if number is too small
    if PageNumber < TotalPages - 4 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      PageItem.classList.add('disabled');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := '...';
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageItem.appendChild(PageLink);
      PaginationElement.appendChild(PageItem);
    end;

    if TotalPages <> 1 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      if TotalPages = PageNumber then
            PageItem.classList.add('selected-number');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := IntToStr(TotalPages);
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
      var
        PageNum: Integer;
      begin
        PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
        PageNumber := PageNum;
        GetOrders(generateSearchOptions());
      end);
    end;
    PageItem.appendChild(PageLink);
    PaginationElement.appendChild(PageItem);
  end;

  // Next Button
  PageItem := TJSHTMLElement(document.createElement('li'));
  PageItem.className := 'page-item';
  if PageNumber = TotalPages then
    PageItem.classList.add('disabled');
  PageLink := TJSHTMLElement(document.createElement('a'));
  PageLink.className := 'page-link';
  PageLink.innerText := 'Next';
  PageLink.setAttribute('href', 'javascript:void(0)');
  PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
  begin
    if PageNumber < TotalPages then
    begin
      Inc(PageNumber);
      GetOrders(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

end;


procedure TFViewOrders.GetOrders(searchOptions: string);
var
  xdcResponse: TXDataClientResponse;
  orderList: TJSObject;
begin
  if PageNumber > 0 then
  begin
    asm
      startSpinner();
    end;
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetOrders', [searchOptions]));
    orderList := TJSObject(xdcResponse.Result);

    // Load data into the dataset
    xdwdsOrders.Close;
    xdwdsOrders.SetJsonData(orderList['data']);
    xdwdsOrders.Open;

    asm
      setTimeout(endSpinner, 2000);
    end;

    lblEntries.Caption := 'Total entries: ' + IntToStr(integer(orderList['count']));
    // Optional: Continue using pagination if needed
    GeneratePagination((integer(orderList['count']) + PageSize - 1) div PageSize);
  end;
end;


procedure TFViewOrders.btnAddOrderClick(Sender: TObject);
begin
  ShowAddOrderForm();
end;


procedure TFViewOrders.orderEntry(orderInfo, customerInfo, mode: string);
begin
  FViewMain.ViewOrderEntry(orderInfo, customerInfo, mode);
end;


procedure TFViewOrders.btnApplyClick(Sender: TObject);
// Button that effectively functions as a GetOrders() button
var
searchOptions: string;
begin
  PageNumber := 1;
  PageSize := 50;
  OrderBy := wcbSortBy.Text;
  searchOptions :=  '&pagenumber=' + IntToStr(PageNumber) +
                    '&pagesize=' + IntToStr(PageSize) +
                    '&orderby=' + OrderBy +
                    '&startDate=' + FormatDateTime('yyyy/mm/dd', dtpStartDate.Date) +
                    '&endDate=' + FormatDateTime('yyyy/mm/dd', dtpEndDate.Date) +
                    '&filterType=' + wcbSortBy.Text;
  GetOrders(searchOptions);
end;


procedure TFViewOrders.btnCloseNotificationClick(Sender: TObject);
begin
  HideNotification();
end;


procedure TFViewOrders.btnConfirmClick(Sender: TObject);
begin
  //orderEntry('', 'ADD');
end;


procedure TFViewOrders.btnFiltersClick(Sender: TObject);
var
filterSection: TJSHTMLElement;
begin
  if btnFilters.Caption = 'Show Filters' then
  begin
    btnFilters.Caption := 'Hide Filters';
    filterSection := TJSHTMLElement(document.getElementById('filter_info'));
    if Assigned(filterSection) then
      filterSection.style.setProperty('display', 'block');
  end
  else
  begin
    btnFilters.Caption := 'Show Filters';
    filterSection := TJSHTMLElement(document.getElementById('filter_info'));
    if Assigned(filterSection) then
      filterSection.style.setProperty('display', 'none');
  end;
end;


procedure TFViewOrders.Search(searchOptions: string);
// Search method that searches the database for a specific phone number
var
  xdcResponse: TXDataClientResponse;
  callList : TJSObject;
  i: integer;
  data: TJSArray;
  call: TJSObject;
  callListLength: integer;

begin
  if PageNumber > 0 then
  begin
    xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.Search',
        [searchOptions]));
    callList :=  TJSObject(xdcResponse.Result);
    data := TJSArray(callList['data']);
    callListLength := integer(callList['count']);
    ClearTable();
    for i := 0 to data.Length - 1 do
    begin
      call := TJSObject(data[i]);
      {AddRowToTable(string(call['toNumber']), string(call['fromNumber']), string(call['dateCreated']),
      string(call['duration']), string(call['transcription']), string(call['mediaUrl']));}
    end;
    TotalPages := (callListLength + PageSize - 1) div PageSize;
    lblEntries.Caption := 'Showing entries for phone number: ' + searchOptions;
  end;
end;


procedure TFViewOrders.btnSearchClick(Sender: TObject);
// orders Search method
begin
  Search(edtSearch.Text);
end;


procedure TFViewOrders.ClearTable();
// clears the table
var
  tbody: TJSHTMLElement;
begin
  tbody := TJSHTMLElement(document.getElementById('tblPhoneGrid').getElementsByTagName('tbody')[0]);
  tbody.innerHTML := '';
end;


function TFViewOrders.GenerateSearchOptions(): string;
// Generates searchOptions for GetOrders.
var
searchOptions: string;
begin
  //PageNumber := 1;
  PageSize := 50;
  OrderBy := wcbSortBy.Text;
  searchOptions :=  '&pagenumber=' + IntToStr(PageNumber) +
                    '&pagesize=' + IntToStr(PageSize) +
                    '&orderby=' + OrderBy;
  if btnFilters.Caption = 'Hide Filters' then
    begin
      searchOptions := searchOptions +
                    '&startDate=' + FormatDateTime('yyyy/mm/dd', dtpStartDate.Date) +
                    '&endDate=' + FormatDateTime('yyyy/mm/dd', dtpEndDate.Date) +
                    '&filterType=' + wcbSortBy.Text;
    end;
  Result := searchOptions;
end;


procedure TFViewOrders.HideNotification;
begin
  pnlMessage.ElementHandle.hidden := True;
  info := '';
end;


procedure TFViewOrders.ShowNotification(Notification: string);
begin
  if Notification <> '' then
  begin
    console.log('hit');
    lblMessage.Caption := Notification;
    pnlMessage.ElementHandle.hidden := False;
  end;
end;


procedure TFViewOrders.GeneratePDF(OrderID: string);
var
  XDCResponse: TXDataClientResponse;
  PDFBase64: string;
  PDFBlob: TJSUint8Array;
  PDFLink: TJSHTMLElement;
begin
//  XDCResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GenerateOrderPDF', [OrderID]));
//  PDFBase64 := string(XDCResponse.Result);
//
//  // Convert Base64 to binary and create a link to download it
//  PDFBlob := TJSUint8Array.new(TJSBase64.decodeBase64(PDFBase64));
//  PDFLink := TJSHTMLElement(document.createElement('a'));
//  PDFLink.setAttribute('href', 'data:application/pdf;base64,' + PDFBase64);
//  PDFLink.setAttribute('download', 'Order_' + OrderID + '.pdf');
//  PDFLink.click;
end;


end.
