/**
 * @brief Functions for making models at PrimitiveCell level.
 *
 * @author Yunhai Li (liyunhai1016@hotmail.com)
 *
 * @copyright Copyright (c) 2025, TBPLaS develop team.
 */

#ifndef TBPLAS_TESTS_MODEL_H
#define TBPLAS_TESTS_MODEL_H

#include <tuple>

#include "builder/analytical.h"
#include "builder/primitive.h"

namespace tbplas::tests {

using base::complex_t;
using builder::AnalyticalModel;
using builder::PrimitiveCell;
using model_t = PrimitiveCell<complex_t>;

/**
 * @brief Make graphene primitive cell with non-zero onsite energies.
 * 
 * @param[in] t hopping integral in eV
 * @param[in] a C-C bond length in NM
 * @param[in] with_onsite whether to use non-zero onsite energies
 * @return graphene primitive cell
 */
model_t make_graphene_pc(
    double t = -2.7,
    double a = 0.142,
    bool with_onsite = false);

/**
 * @brief Make a large graphene model by extending the primitive cell.
 * 
 * @param[in] t hopping integral in eV
 * @param[in] a C-C bond length in NM
 * @param[in] with_onsite whether to use non-zero onsite energies
 * @param[in] dim dimension of the model
 * @return graphene model with given dimension
 */
model_t make_graphene(
    double t = -2.7,
    double a = 0.142,
    bool with_onsite = false,
    const std::tuple<int, int, int>& dim = { 1024, 1024, 1 });

/**
 * @brief Make an overlap for given primitive cell.
 * 
 * @param[in] model primitive cell from which the overlap will be generated
 * @return model_t overlap with the same numbers of orbitals and hopping terms as the model
 */
model_t make_overlap(const model_t& model);

/**
 * @brief Make Haldane model for testing Berry utilities.
 * 
 * @return Haldane model
 */
model_t make_haldane();

/**
 * @brief Make twisted bi-layer graphene (tbg).
 * 
 * @param[in] tbg_idx index of twisting angle
 * @return tbg model 
 */
model_t make_tbg(int tbg_idx = 5);

/**
 * @brief Make quasi-crystal model with given radius.
 * 
 * @param[in] radius radius of quasi-crystal in NM
 * @return quasi-crystal model
 */
model_t make_quasi_crystal(double radius = 3.0);

/**
 * @brief Make square sierpinski carpet model.
 * 
 * @param[in] iteration of the model
 * @return square sierpinski carpet model.
 */
model_t make_fractal(int iteration = 3);

/**
 * @brief Analytical QAH model for testing Berry utilities.
 * @note Ref: https://www.guanjihuan.com/archives/3932.
 */
class QAH : public AnalyticalModel {
public:
    QAH();

    void build_ham_dense(
        const Eigen::Vector3d& k_point,
        Eigen::MatrixXcd& ham,
        int convention = 1) const;

    void build_ham_der_dense(
        const Eigen::Vector3d& k_point,
        Eigen::MatrixXcd& dh_dka,
        Eigen::MatrixXcd& dh_dkb,
        Eigen::MatrixXcd& dh_dkc,
        int convention = 1) const;
};

/**
 * @brief Analytical CheckerBoard model for testing Berry utilities.
 * @note Ref: https://www.guanjihuan.com/archives/23989
 */
class CheckerBoard : public AnalyticalModel {
public:
    explicit CheckerBoard(int ny);

    void build_ham_dense(
        const Eigen::Vector3d& k_point,
        Eigen::MatrixXcd& ham,
        int convention = 1) const;

private:
    int ny_ = 5;
};

/**
 * @brief Analytical Haldane model for testing Berry utilities.
 * @note Ref: https://www.guanjihuan.com/archives/5133
 */
class Haldane : public AnalyticalModel {
public:
    Haldane();

    void build_ham_dense(
        const Eigen::Vector3d& k_point,
        Eigen::MatrixXcd& ham,
        int convention = 1) const;
};
} // namespace tbplas::tests
#endif
