#pragma once

#include "fesa/model/model_types.hpp"

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

namespace fesa {

struct StepFrameIdentity {
    std::string stepName;
    std::size_t frameIndex;
};

struct EndpointResultRow {
    EntityIndex element;
    int endpoint;
    SourceEntityId node;
    std::array<double, 6> endAction;
    std::array<double, 4> sectionResultant;
};

struct GaussResultRow {
    EntityIndex element;
    int gaussPoint;
    std::array<double, 4> generalizedStrain;
    std::array<double, 4> generalizedResultant;
};

struct StressS11Row {
    EntityIndex element;
    int gaussPoint;
    std::size_t sectionPoint;
    double x1;
    double x2;
    double s11;
    std::string source;
};

enum class ShellMidsurfaceLocation {
    gp1,
    gp2,
    gp3,
    gp4
};

enum class ShellSectionPosition {
    bottom,
    middle,
    top
};

struct ShellSectionStressRow {
    ShellSectionPosition position;
    double zeta;
    std::array<double, 3> components;
};

struct ShellResultRow {
    EntityIndex element;
    ShellMidsurfaceLocation location;
    std::array<double, 2> naturalCoordinates;
    // Axis rows [e1,e2,e3], global-component columns.
    std::array<std::array<double, 3>, 3> localFrame;
    std::array<double, 8> generalizedStrain;
    std::array<double, 8> sectionResultant;
    // Fixed BOTTOM, MIDDLE, TOP order; components are [S11,S22,S12].
    std::array<ShellSectionStressRow, 3> stress;
};

struct ShellStateCandidate {
    std::vector<ShellResultRow> rows;
    double physicalStrainEnergy{0.0};
    // [FORCE_1,FORCE_2,FORCE_3,MOMENT_1,MOMENT_2,MOMENT_3].
    std::array<double, 6> equilibrium{};
    // [FREE_RESIDUAL_NORMALIZED,FORCE_BALANCE_NORMALIZED,
    //  MOMENT_BALANCE_NORMALIZED].
    std::array<double, 3> verificationMetrics{};
};

} // namespace fesa
