/*
Copyright (©) 2003-2026 Teus Benschop.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#include <config/libraries.h>
#ifdef HAVE_GTEST
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wcharacter-conversion"
#include "gtest/gtest.h"
#pragma GCC diagnostic pop
#include <unittests/utilities.h>
#include <webserver/request.h>
#include <ipc/notes.h>
#include <ipc/focus.h>
#include <filter/string.h>


TEST (ipc, basic)
{
  // Initialize.
  refresh_sandbox (false);
  Webserver_Request webserver_request;
  webserver_request.database_users ()->create ();
  webserver_request.session_logic ()->set_username ("phpunit");
  
  // There should be no note identifier.
  int identifier = Ipc_Notes::get (webserver_request);
  EXPECT_EQ (0, identifier);
  
  // Test opening note.
  Ipc_Notes::open (webserver_request, 123456789);
  identifier = Ipc_Notes::get (webserver_request);
  EXPECT_EQ (123456789, identifier);
  
  // Test trimming.
  webserver_request.database_ipc()->trim ();
  identifier = Ipc_Notes::get (webserver_request);
  EXPECT_EQ (123456789, identifier);
  
  // Test deleting note once.
  Ipc_Notes::open (webserver_request, 123456789);
  Ipc_Notes::erase (webserver_request);
  identifier = Ipc_Notes::get (webserver_request);
  EXPECT_EQ (0, identifier);
  
  // Test deleting two notes.
  Ipc_Notes::open (webserver_request, 123456789);
  Ipc_Notes::open (webserver_request, 123456789);
  Ipc_Notes::erase (webserver_request);
  identifier = Ipc_Notes::get (webserver_request);
  EXPECT_EQ (0, identifier);
  Ipc_Notes::erase (webserver_request);
  identifier = Ipc_Notes::get (webserver_request);
  EXPECT_EQ (0, identifier);
}


TEST (database, ipc)
{
  // Test trim.
  {
    refresh_sandbox (false);
    Webserver_Request webserver_request;
    Database_Ipc database_ipc (webserver_request);
    database_ipc.trim ();
  }

  // Test store retrieve
  {
    refresh_sandbox (true);
    Webserver_Request webserver_request;
    Database_Ipc database_ipc (webserver_request);
    
    int id = 1;
    std::string user = "phpunit";
    std::string channel = "channel";
    std::string command = "command";
    std::string message = "message";
    
    database_ipc.storeMessage (user, channel, command, message);
    
    Database_Ipc_Message data = database_ipc.retrieveMessage (id, user, channel, command);
    EXPECT_EQ (0, data.id);
    
    database_ipc.storeMessage (user, channel, command, message);
    
    data = database_ipc.retrieveMessage (id, user, channel, command);
    EXPECT_EQ (2, data.id);
    EXPECT_EQ (message, data.message);
  }

  // Test delete
  {
    refresh_sandbox (true);
    Webserver_Request webserver_request;
    Database_Ipc database_ipc (webserver_request);
    
    int id = 1;
    std::string user = "phpunit";
    std::string channel = "channel";
    std::string command = "command";
    std::string message = "message";
    
    database_ipc.storeMessage (user, channel, command, message);
    
    Database_Ipc_Message data = database_ipc.retrieveMessage (0, user, channel, command);
    EXPECT_EQ (id, data.id);
    
    database_ipc.deleteMessage (id);
    
    data = database_ipc.retrieveMessage (0, user, channel, command);
    EXPECT_EQ (0, data.id);
  }

  // Test get note.
  {
    refresh_sandbox (true);
    Database_Users database_users;
    database_users.create ();
    Webserver_Request webserver_request;
    Database_Ipc database_ipc (webserver_request);
    
    std::string user = "phpunit";
    webserver_request.session_logic ()->set_username (user);
    std::string channel = "channel";
    std::string command = "opennote";
    
    Database_Ipc_Message note = database_ipc.getNote ();
    EXPECT_EQ (0, note.id);
    
    std::string message = "12345";
    database_ipc.storeMessage (user, channel, command, message);
    note = database_ipc.getNote ();
    EXPECT_EQ (message, note.message);
    
    message = "54321";
    database_ipc.storeMessage (user, channel, command, message);
    note = database_ipc.getNote ();
    EXPECT_EQ (message, note.message);
  }

  // Test notes alive.
  {
    refresh_sandbox (true);
    Database_Users database_users;
    database_users.create ();
    Webserver_Request webserver_request;
    Database_Ipc database_ipc (webserver_request);
    
    std::string user = "phpunit";
    webserver_request.session_logic ()->set_username (user);
    std::string channel = "channel";
    std::string command = "notesalive";
    
    bool alive = database_ipc.getNotesAlive ();
    EXPECT_EQ (false, alive);
    
    std::string message = "1";
    database_ipc.storeMessage (user, channel, command, message);
    alive = database_ipc.getNotesAlive ();
    EXPECT_EQ (filter::string::convert_to_bool (message), alive);
    
    message = "0";
    database_ipc.storeMessage (user, channel, command, message);
    alive = database_ipc.getNotesAlive ();
    EXPECT_EQ (filter::string::convert_to_bool (message), alive);
  }
}


TEST (ipc, focus)
{
  // Initialize.
  refresh_sandbox (false);
  Webserver_Request req;
  req.session_logic()->set_username("gtest");
  Webserver_Request other_req;
  other_req.session_logic()->set_username("other");

  // Verify the initial passage is Genesis 1.1.
  EXPECT_EQ (ipc_focus::get_book(req), 1);
  EXPECT_EQ (ipc_focus::get_chapter(req), 1);
  EXPECT_EQ (ipc_focus::get_verse(req), 1);
  EXPECT_EQ (ipc_focus::get_book(other_req), 1);
  EXPECT_EQ (ipc_focus::get_chapter(other_req), 1);
  EXPECT_EQ (ipc_focus::get_verse(other_req), 1);

  // Set a passage and confirm it.
  constexpr const int book {2};
  constexpr const int chapter {3};
  constexpr const int verse {4};
  ipc_focus::set_passage(req, book, chapter, verse);
  EXPECT_EQ (ipc_focus::get_book(req), book);
  EXPECT_EQ (ipc_focus::get_chapter(req), chapter);
  EXPECT_EQ (ipc_focus::get_verse(req), verse);
  EXPECT_EQ (ipc_focus::get_book(other_req), 1);
  EXPECT_EQ (ipc_focus::get_chapter(other_req), 1);
  EXPECT_EQ (ipc_focus::get_verse(other_req), 1);
  
  // Update the webserver request to now refer to another focus group.
  req.query[ipc_focus::focusgroup] = "5";

  // Verify the initial passage in the set focus group is Genesis 1.1.
  EXPECT_EQ (ipc_focus::get_book(req), 1);
  EXPECT_EQ (ipc_focus::get_chapter(req), 1);
  EXPECT_EQ (ipc_focus::get_verse(req), 1);

  // Set a passage in the focus group and confirm it.
  ipc_focus::set_passage(req, book, chapter, verse);
  EXPECT_EQ (ipc_focus::get_book(req), book);
  EXPECT_EQ (ipc_focus::get_chapter(req), chapter);
  EXPECT_EQ (ipc_focus::get_verse(req), verse);
  EXPECT_EQ (ipc_focus::get_book(other_req), 1);
  EXPECT_EQ (ipc_focus::get_chapter(other_req), 1);
  EXPECT_EQ (ipc_focus::get_verse(other_req), 1);
  
  // Test the behaviour of the function to get the focus group from the webserver request.
  // * Default focus group: 0.
  // * If focus group out of bounds: 0.
  // * Focus group within bounds: n.
  req.query.erase(ipc_focus::focusgroup);
  EXPECT_EQ(ipc_focus::get_focus_group(req), 0);
  req.query[ipc_focus::focusgroup] = "-1";
  EXPECT_EQ(ipc_focus::get_focus_group(req), 0);
  req.query[ipc_focus::focusgroup] = "10";
  EXPECT_EQ(ipc_focus::get_focus_group(req), 0);
  req.query[ipc_focus::focusgroup] = "2";
  EXPECT_EQ(ipc_focus::get_focus_group(req), 2);
  req.query[ipc_focus::focusgroup] = "9";
  EXPECT_EQ(ipc_focus::get_focus_group(req), 9);
}


#endif
