//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Particle/DwbaChannels.h
//! @brief     Defines scalar and polarized DWBA channel types and extraction.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2026
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifdef SWIG
#error no need to expose this header to Swig
#endif
#ifndef BORNAGAIN_SAMPLE_PARTICLE_DWBACHANNELS_H
#define BORNAGAIN_SAMPLE_PARTICLE_DWBACHANNELS_H

#include "Base/Spin/SpinMatrix.h"
#include "Base/Spin/Spinor.h"
#include "Base/Vector/WavevectorInfo.h"
#include <array>
#include <cstddef>
#include <heinz/Complex.h>

class DiffuseElement;

//! Number of scalar DWBA channels (TT, RT, TR, RR).
inline constexpr size_t N_DWBA = 4;

//! DWBA channel wavevectors and weights for a single pixel/slice.
//!
//! q holds N_DWBA WavevectorInfo objects corresponding to:
//!   q[0]=TT, q[1]=RT, q[2]=TR, q[3]=RR
//! with weights w[m] = (T_in or R_in) * (T_out or R_out).
//! In Born approximation (no interface) only channel 0 is active.
struct DwbaChannels {
    std::array<WavevectorInfo, N_DWBA> q; //!< N_DWBA wavevectors
    std::array<complex_t, N_DWBA> w{};    //!< DWBA weights
    size_t n_active{N_DWBA};              //!< Number of valid leading channels.
};

//! Per-channel first and second moments of a scattering object F.
//!
//! mu[m]   = <F(q[m])>
//! C[m][n] = <(F(q[m]) - mu[m]) * conj(F(q[n]) - mu[n])>  (Hermitian)
//!
//! These are per-channel moments, to be contracted with DWBA weights.
struct ChannelMoments {
    std::array<complex_t, N_DWBA> mu{};
    std::array<std::array<complex_t, N_DWBA>, N_DWBA> C{};
};

//! Array of DWBA weights from the slice.
//!
//! Provides the packed DWBA weights paired with corresponding q-vectors at the given slice
//! ready for contraction with form factors.
DwbaChannels extractDwbaChannels(const DiffuseElement& ele, size_t i_slice);

// --- Polarized DWBA channels (16 channels) ---

//! Number of polarized DWBA channels (2 eigenmodes_in × 2 eigenmodes_out × 4 T/R).
inline constexpr size_t N_POL_DWBA = 16;

//! Per-channel flux spinors that define the DWBA weight operator W_m.
//!
//! W_m(F) = SpinMatrix(
//!     -Spinor::dotProduct(out_minus, F * in_plus),
//!     +Spinor::dotProduct(out_plus,  F * in_plus),
//!     -Spinor::dotProduct(out_minus, F * in_minus),
//!     +Spinor::dotProduct(out_plus,  F * in_minus))
struct PolChannelFlux {
    Spinor in_plus;
    Spinor in_minus;
    Spinor out_plus;
    Spinor out_minus;
};

//! Polarized DWBA channel wavevectors, per-channel flux spinors, and polarizer.
struct PolDwbaChannels {
    std::array<WavevectorInfo, N_POL_DWBA> q;
    std::array<PolChannelFlux, N_POL_DWBA> flux;
    SpinMatrix polarizer;
    size_t n_active{N_POL_DWBA}; //!< Number of valid leading channels.
};

//! Applies the DWBA weight operator W_m to a SpinMatrix form factor F.
SpinMatrix applyWeight(const SpinMatrix& F, const PolChannelFlux& flux);

//! Per-channel polarized moments of a scattering object F.
//!
//! mu[m]   = <F(q[m])>  (SpinMatrix)
//! C[m][n] = <W_m(ΔF_m) · P · W_n(ΔF_n)†>  (SpinMatrix, contracted with W and P)
//!
//! The contracted form allows the mesocrystal to multiply C by the scalar
//! transfer factor T[m][n] without needing the full component-wise covariance.
struct PolChannelMoments {
    std::array<SpinMatrix, N_POL_DWBA> mu;
    std::array<std::array<SpinMatrix, N_POL_DWBA>, N_POL_DWBA> C;
};

//! Array of DWBA polarized flux weights from the slice.
//!
//! Provides the packed polarized DWBA fluxes paired with corresponding q-vectors at the given slice
//! ready for contraction with form factors.
PolDwbaChannels extractPolDwbaChannels(const DiffuseElement& ele, size_t i_slice);

#endif // BORNAGAIN_SAMPLE_PARTICLE_DWBACHANNELS_H
