#pragma once

#include "fesa/analysis/analysis_model.hpp"
#include "fesa/analysis/analysis_state.hpp"
#include "fesa/constraints/essential_constraints.hpp"
#include "fesa/core/status.hpp"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/math/sparse_matrix.hpp"
#include "fesa/math/vector.hpp"
#include "fesa/model/domain.hpp"

#include <filesystem>
#include <memory>
#include <vector>

namespace fesa {

class LinearSolver;
class ParallelFor;
class ResultsWriter;

struct AnalysisRequest {
    std::filesystem::path inputPath;
    std::filesystem::path outputPath;
};

// Fixes the public V0 lifecycle while leaving each analysis procedure to
// implement its approved stages.
class Analysis {
public:
    virtual ~Analysis() = default;
    Status run(const AnalysisRequest& request);

protected:
    virtual Status initialize(const AnalysisRequest& request) = 0;
    virtual Status buildAnalysisModel() = 0;
    virtual Status buildDofMapAndSparsePattern() = 0;
    virtual Status assembleAndPartitionStiffness() = 0;
    virtual Status factorize() = 0;
    virtual Status assembleLoadsAndEffectiveRhs() = 0;
    virtual Status substituteAndReconstruct() = 0;
    virtual Status recoverAndWriteResults() = 0;
};

// Orchestrates the single-step B33 procedure through injected backend
// boundaries so factorization and substitution remain independently visible.
class LinearStaticAnalysis final : public Analysis {
public:
    LinearStaticAnalysis(const ParallelFor& parallelFor,
                         LinearSolver& linearSolver,
                         ResultsWriter& resultsWriter);

protected:
    Status initialize(const AnalysisRequest& request) override;
    Status buildAnalysisModel() override;
    Status buildDofMapAndSparsePattern() override;
    Status assembleAndPartitionStiffness() override;
    Status factorize() override;
    Status assembleLoadsAndEffectiveRhs() override;
    Status substituteAndReconstruct() override;
    Status recoverAndWriteResults() override;

private:
    const ParallelFor& parallelFor_;
    LinearSolver& linearSolver_;
    ResultsWriter& resultsWriter_;
    AnalysisRequest request_;
    std::unique_ptr<Domain> domain_;
    std::unique_ptr<AnalysisModel> model_;
    std::unique_ptr<DofManager> dofs_;
    std::unique_ptr<AnalysisState> state_;
    std::unique_ptr<SparseMatrix> fullStiffness_;
    std::unique_ptr<PartitionedStiffness> partitionedStiffness_;
    std::unique_ptr<Vector> effectiveRhs_;
    std::vector<Diagnostic> diagnostics_;
};

} // namespace fesa
