#ifndef TBPLAS_SAMPLE_H
#define TBPLAS_SAMPLE_H
#include <cmath>
#include <complex>
#include <cstdint>

#include "memory_view.h"

namespace sample {
using complex_t = std::complex<double>;
using memory_view::MemoryView;
using memory_view::ConstMemoryView;

inline void apply_mag_field_cxx(
    int64_t num_hop_sc,
    const int64_t* hop_ind,
    complex_t* hop_eng,
    const double* dr,
    const double* orb_pos,
    double intensity,
    int64_t gauge)
{
    constexpr double pi = 3.14159265358979323846;
    constexpr double factor = pi / 4135.666734;
    int64_t ii = 0;
    int64_t jj = 0;
    double dx = 0.0;
    double dy = 0.0;
    double sx = 0.0;
    double sy = 0.0;
    double phase = 0.0;

    ConstMemoryView<int64_t> hop_ind_map(hop_ind, 2);
    MemoryView<complex_t> hop_eng_map(hop_eng, 1);
    ConstMemoryView<double> dr_map(dr, 3);
    ConstMemoryView<double> orb_pos_map(orb_pos, 3);

    if (gauge == 0) {
#pragma omp parallel for private(ii, jj, dx, sy, phase)
        for (int64_t ih = 0; ih < num_hop_sc; ++ih) {
            ii = hop_ind_map(ih, 0);
            jj = hop_ind_map(ih, 1);
            dx = dr_map(ih, 0);
            sy = orb_pos_map(jj, 1) + orb_pos_map(ii, 1);
            phase = factor * intensity * dx * sy;
            hop_eng_map(ih) *= complex_t(cos(phase), sin(phase));
        }
    } else if (gauge == 1) {
#pragma omp parallel for private(ii, jj, dy, sx, phase)
        for (int64_t ih = 0; ih < num_hop_sc; ++ih) {
            ii = hop_ind_map(ih, 0);
            jj = hop_ind_map(ih, 1);
            dy = dr_map(ih, 1);
            sx = orb_pos_map(jj, 0) + orb_pos_map(ii, 0);
            phase = -factor * intensity * dy * sx;
            hop_eng_map(ih) *= complex_t(cos(phase), sin(phase));
        }
    } else {
#pragma omp parallel for private(ii, jj, dx, dy, sx, sy, phase)
        for (int64_t ih = 0; ih < num_hop_sc; ++ih) {
            ii = hop_ind_map(ih, 0);
            jj = hop_ind_map(ih, 1);
            dx = dr_map(ih, 0);
            dy = dr_map(ih, 1);
            sx = orb_pos_map(jj, 0) + orb_pos_map(ii, 0);
            sy = orb_pos_map(jj, 1) + orb_pos_map(ii, 1);
            phase = factor * 0.5 * intensity * (dx * sx - dy * sy);
            hop_eng_map(ih) *= complex_t(cos(phase), sin(phase));
        }
    }
}
} // namespace sample
#endif