/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#ifndef CAMITK_TESTTRANSFORMATIONEXPLORER_H
#define CAMITK_TESTTRANSFORMATIONEXPLORER_H

#include <QTest>

#include <ranges>

#include "FrameOfReference.h"
#include "Transformation.h"
#include "TransformationManager.h"
#include "MeshComponent.h"
#include "Application.h"
#include "ExtensionManager.h"
#include "TransformationExplorer.h"
#include "Log.h"

#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>


using namespace camitk;

class TestTransformationExplorer: public QObject {
    Q_OBJECT

    TransformationExplorer* explorer;

    /**
     * Create two frames and a Transformation linking them for testing
     */
    auto createFramesAndTransformation(QString frame1, QString frame2) {
        auto fr1 = TransformationManager::addFrameOfReference(frame1);
        auto fr2 = TransformationManager::addFrameOfReference(frame2);

        auto tr = TransformationManager::addTransformation(fr1, fr2);
        return std::make_tuple(fr1, fr2, tr);
    }

    /**
     * Create a basic MeshComponent for tests
     */
    Component* createSphere(float radius = 1.0) {
        auto sphereSource = vtkSmartPointer<vtkSphereSource>::New();
        sphereSource->SetRadius(radius);
        vtkSmartPointer<vtkPointSet> sphere(sphereSource->GetOutput());
        return new MeshComponent(sphere, "Sphere");
    }

private slots:

    /// Before all tests, create a TransformationManager
    void initTestCase() {
        // show all log messages in the console
        Log::getLogger()->setLogLevel(InterfaceLogger::TRACE);
        // no log messages will generate a QMessageBox
        Log::getLogger()->setMessageBoxLevel(InterfaceLogger::NONE);
        // no time stamp for reproducible log diff
        Log::getLogger()->setTimeStampInformation(false);

        // Make sure we load the TransformationExplorer viewer
        // Load all the viewer extensions in order to use the TransformationExplorer factory (Application::getNewViewer)
        ExtensionManager::autoload(ExtensionManager::VIEWER);
        // Create a new custom Geometry Viewer
        explorer = dynamic_cast<TransformationExplorer*>(Application::getNewViewer("Explorer test", "TransformationExplorer"));
        QVERIFY(explorer != nullptr);

        // Initialize the widget and show the widget in order to build the widget (and its frame)
        // and force the new viewer frame to be truly visible so that calling setFrame(..)
        // (that itself calls refresh(..)) really updates of the actor transformation, the aim of this test
        explorer->getWidget();

        // Register the viewer so that it can be used in comp->setVisibility(...)
        // and be automatically called during Application::refresh()
        Application::registerViewer(explorer);
    }

    /// Run after testing (failed or not)
    void cleanupTestCase() {
    }

    /// Cleanup after each test
    void cleanup() {

    }

    /// Test FrameOfReference constructors
    void playWithFramesTransformationsAndComponents() {
        explorer->refresh();
        auto [fr1, fr2, tr] = createFramesAndTransformation("Frame1", "Frame2");
        explorer->refresh();
        Component* c1 = createSphere();
        QVERIFY(c1 != nullptr);
        explorer->refresh();
        delete c1;
        explorer->refresh();
        fr1 = nullptr;
        fr2 = nullptr;
        tr = nullptr;
        TransformationManager::cleanupFramesAndTransformations();
        explorer->refresh();
        QCOMPARE(TransformationManager::getFramesOfReference().size(), 1);
    }

};

// } // namespace camitk

#endif // CAMITK_TESTTRANSFORMATIONEXPLORER_H
