#pragma once

#include "fesa/core/status.hpp"
#include "fesa/math/vector.hpp"

#include <cstddef>
#include <vector>

namespace fesa {

struct SparsePattern;

struct CooContribution {
    std::size_t row;
    std::size_t column;
    double value;
    std::size_t elementOrder;
    std::size_t localOrder;
};

// Owns canonical 0-based CSR data independently of the dense Matrix adapter.
class SparseMatrix {
public:
    static Result<SparseMatrix> fromCoo(
        std::size_t rows,
        std::size_t columns,
        std::vector<CooContribution> contributions,
        const SparsePattern& expectedPattern);

    std::size_t rows() const noexcept;
    std::size_t columns() const noexcept;
    const std::vector<std::size_t>& rowOffsets() const noexcept;
    const std::vector<std::size_t>& columnIndices() const noexcept;
    const std::vector<double>& values() const noexcept;
    Vector multiply(const Vector& rhs) const;
    Status validate() const;

private:
    SparseMatrix(
        std::size_t rows,
        std::size_t columns,
        std::vector<std::size_t> rowOffsets,
        std::vector<std::size_t> columnIndices,
        std::vector<double> values);

    std::size_t rows_;
    std::size_t columns_;
    std::vector<std::size_t> rowOffsets_;
    std::vector<std::size_t> columnIndices_;
    std::vector<double> values_;
};

} // namespace fesa
