#pragma once

#include "mfem.hpp"

namespace serif::utilities {
    [[nodiscard]] mfem::SparseMatrix build_reduced_matrix(
        const mfem::SparseMatrix& matrix,
        const mfem::Array<int>& trialEssentialDofs,
        const mfem::Array<int>& testEssentialDofs
    );

    /**
     * @brief Generate a vector of 1s and 0s where 1 elemetns cooresponds to queried dofs. Useful for degugging
     * @param allDofs array, counding from 0, of all dofs in the system
     * @param highlightDofs the dofs that you want to identify
     * @return
     *
     * *Example Usage:*
     * One could use this to identify, for example, which dofs are being identified as the central dofs
     * @code
     * ...
     * mfem::Array<int> phiDofs, thetaDofs;
     * phiDofs.SetSize(m_fePhi->GetNDofs());
     * thetaDofs.SetSize(m_feTheta->GetNDofs());
     * const mfem::Vector phiHighlightVector = serif::utilities::build_dof_identification_vector(phiDofs, phiCenterDofs);
     * const mfem::Vector thetaHighlightVector = serif::utilities::build_dof_identification_vector(thetaDofs, thetaCenterDofs);
     * Probe::glVisView(
     *     const_cast<mfem::Vector&>(phiHighlightVector),
     *     *m_fePhi,
     *     "Phi Center Dofs"
     *     );
     * Probe::glVisView(
     *     const_cast<mfem::Vector&>(thetaHighlightVector),
     *     *m_feTheta,
     *     "Theta Center Dofs"
     *     );
     * @endcode
     */
    mfem::Vector build_dof_identification_vector(
        const mfem::Array<int>& allDofs,
        const::mfem::Array<int>& highlightDofs
        );

    /**
     * @brief Computes the curl of a given H(div) grid function (e.g., from an RT space).
     *
     * This function is crucial for diagnosing spurious, non-physical modes in mixed FEM
     * formulations where the curl of a gradient field is expected to be zero.
     *
     * @param phi_gf The GridFunction representing the vector field (e.g., φ). It is expected
     * to be in an H(div)-conforming space like Raviart-Thomas (RT).
     * @return A std::pair containing two new grid functions:
     * - pair.first: A unique_ptr to the vector curl field (∇ × φ). This field will
     * be in an H(curl)-conforming Nedelec (ND) space.
     * - pair.second: A unique_ptr to the scalar magnitude of the curl (||∇ × φ||).
     * This field will be in an L2 space.
     *
     * @note The returned unique_ptrs manage the lifetime of the new GridFunctions and their
     * associated FiniteElementSpaces and FECollections, preventing memory leaks.
     */
    mfem::GridFunction compute_curl(mfem::GridFunction& phi_gf);
}
