#pragma once

#include <cstdint>
#include <cstddef>
#include <vector>
#include <stdexcept>

namespace paritypp {

// Matrix over GF(2^8) for Reed-Solomon encoding/decoding
class matrix {
public:
    matrix(size_t rows, size_t cols);
    matrix(const matrix& other);
    matrix& operator=(const matrix& other);

    size_t rows() const { return rows_; }
    size_t cols() const { return cols_; }

    uint8_t& at(size_t r, size_t c);
    uint8_t  at(size_t r, size_t c) const;

    // Create identity matrix
    static matrix identity(size_t n);

    // Create Vandermonde matrix (rows x cols) for encoding
    static matrix vandermonde(size_t rows, size_t cols);

    // Create Cauchy matrix (rows x cols) for encoding
    static matrix cauchy(size_t rows, size_t cols);

    // Extract submatrix from given row/col indices
    matrix submatrix(const std::vector<size_t>& row_indices,
                     const std::vector<size_t>& col_indices) const;

    // Extract rows [start, start+count)
    matrix row_slice(size_t start, size_t count) const;

    // Matrix multiplication over GF(2^8)
    matrix multiply(const matrix& other) const;

    // Invert square matrix via Gauss-Jordan elimination in GF(2^8)
    matrix invert() const;

    // Augment: [this | other]
    matrix augment(const matrix& other) const;

private:
    size_t rows_;
    size_t cols_;
    std::vector<uint8_t> data_;
};

} // namespace paritypp
