#pragma once

#include "fesa/core/status.hpp"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/math/vector.hpp"
#include "fesa/results/result_records.hpp"

#include <array>
#include <cstddef>
#include <vector>

namespace fesa {

// Owns only the mutable quantities required by the V0 linear-static frame.
class AnalysisState {
public:
    static AnalysisState create(
        const DofManager& dofs, StepFrameIdentity identity);

    Vector& displacement() noexcept;
    const Vector& displacement() const noexcept;
    Vector& externalForce() noexcept;
    const Vector& externalForce() const noexcept;
    Vector& internalForce() noexcept;
    const Vector& internalForce() const noexcept;
    Vector& residual() noexcept;
    const Vector& residual() const noexcept;
    Vector& reaction() noexcept;
    const Vector& reaction() const noexcept;
    const StepFrameIdentity& identity() const noexcept;
    std::vector<EndpointResultRow>& endpointResults() noexcept;
    const std::vector<EndpointResultRow>& endpointResults() const noexcept;
    std::vector<GaussResultRow>& gaussResults() noexcept;
    const std::vector<GaussResultRow>& gaussResults() const noexcept;
    std::vector<StressS11Row>& stressResults() noexcept;
    const std::vector<StressS11Row>& stressResults() const noexcept;
    Status commitShellResults(
        const std::vector<EntityIndex>& expectedElementOrder,
        ShellStateCandidate candidate);
    const std::vector<ShellResultRow>& shellResults() const noexcept;
    double physicalStrainEnergy() const noexcept;
    const std::array<double, 6>& equilibrium() const noexcept;
    const std::array<double, 3>& verificationMetrics() const noexcept;

private:
    AnalysisState(std::size_t fullDofCount, StepFrameIdentity identity);

    StepFrameIdentity identity_;
    Vector displacement_;
    Vector externalForce_;
    Vector internalForce_;
    Vector residual_;
    // Reactions retain full-index space so free residual components remain visible.
    Vector reaction_;
    // Recovery appends rows in stable element/location order.
    std::vector<EndpointResultRow> endpointResults_;
    std::vector<GaussResultRow> gaussResults_;
    std::vector<StressS11Row> stressResults_;
    // Shell recovery is replaced only through validated candidate commit.
    std::vector<ShellResultRow> shellResults_;
    double physicalStrainEnergy_{0.0};
    std::array<double, 6> equilibrium_{};
    std::array<double, 3> verificationMetrics_{};
};

} // namespace fesa
