#include "requirementItem.h"

#include "requirementManager.h"

using namespace std;
using namespace core::project;
//--------------------------------------------------------------
/* Constructor */
RequirementItem::RequirementItem(RequirementManager &manager, const std::shared_ptr<RequirementItem> &parentRequirement)
  : m_requirementManager(manager)
{
  // Initialization
  metadata.uuid = m_requirementManager.generateUniqueUuid();     // Generate a unique UUID for this requirement item
  m_parent      = parentRequirement;                             // Set the m_parent requirement item

  // Register this requirement item in the manager's internal map
  m_requirementManager.registerRequirement(shared_from_this());
}
//--------------------------------------------------------------
/* Convert this requirement item to an api::requirement::Requirement struct and return it */
api::requirement::Requirement RequirementItem::toRequirement() const
{
  return { .metadata       = metadata,
           .details        = details,
           .classification = classification };
}
//--------------------------------------------------------------
/* Update the data of this requirement item with the provided updated requirement data */
void RequirementItem::update(const api::requirement::Requirement &updatedData)
{
  const auto currentUUID = metadata.uuid;     // Store the current UUID before updating

  // Update the requirement data with the provided updated requirement data
  metadata       = updatedData.metadata;
  details        = updatedData.details;
  classification = updatedData.classification;

  // Restore the original UUID to maintain consistency
  metadata.uuid = currentUUID;
}
//--------------------------------------------------------------
/* Get the m_parent requirement item of this requirement item (nullptr for root) */
RequirementItem::RequirementItemPtr RequirementItem::getParent() const
{
  // Return the m_parent requirement item pointer if it exists
  // or nullptr if this requirement item is the root
  return m_parent.lock();
}
//--------------------------------------------------------------
/* Append a child requirement item to this requirement item */
void RequirementItem::appendChild(const Requirement &child)
{
  // Create a new requirement item for the child requirement and set this requirement item as its m_parent
  const auto childItem = make_shared<RequirementItem>(m_requirementManager, shared_from_this());
  childItem->update(child);     // Update the child requirement item with the provided child requirement data

  // Append the child requirement item to the vector of children
  m_children.push_back(childItem);
}
//--------------------------------------------------------------
/* Remove a child requirement item from this requirement item by its UUID */
void RequirementItem::removeChild(const std::string &childUuid)
{
  // Unregister the child requirement item from the manager's internal map
  m_requirementManager.unregisterRequirement(childUuid);

  // Find the child requirement item with the given UUID
  const auto childIt = ranges::find_if(m_children,
                                       [&childUuid](const RequirementItemPtr &child)
                                       { return child->metadata.uuid == childUuid; });
  if (childIt == m_children.end())
    throw std::runtime_error("Child requirement item with UUID " + childUuid + " not found");

  (*childIt)->removeChildren();     // Recursively remove all child requirement items of the child requirement item to be removed
  m_children.erase(childIt);        // Remove the child requirement item from the vector of children
}
//--------------------------------------------------------------
/* Remove all child requirement items from this requirement item */
void RequirementItem::removeChildren()
{
  while (!m_children.empty())
  {
    const auto child = m_children.back();     // Get the last child requirement item
    removeChild(child->metadata.uuid);
  }
}
//--------------------------------------------------------------
/* Get the vector of child requirement items of this requirement item */
std::vector<RequirementItem::RequirementItemPtr> RequirementItem::getChildren() const
{
  return m_children;
}
//--------------------------------------------------------------
