#include <iostream>
#include <list>
#include "../../../sources/builder/advanced.h"
#include "../../../sources/builder/build_ham_dxy.h"
#include "../../../sources/builder/primitive.h"
#include "../../../sources/tbpm/solver.h"

#include <Eigen/Dense>
#include <QDir>
#include <QSettings>
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <fstream>
#include <cmath>
#include <string>
#include <tuple>
#include <complex>
using namespace tbplas::base;
using namespace tbplas::builder;

#define M_PI  3.14159265358979323846 // 这是一个很好的近似值

namespace {

    // Function to calculate hopping term
    double calc_hop(const Term& term) {
        constexpr double a0 = 0.1418; // Distance parameter
        constexpr double a1 = 0.3349; // Distance parameter
        constexpr double r_c = 0.6140; // Cutoff radius
        constexpr double l_c = 0.0265; // Smoothing parameter
        constexpr double gamma0 = 2.7; // Interaction strength for pi bonds
        constexpr double gamma1 = 0.48; // Interaction strength for sigma bonds
        constexpr double decay = 22.18; // Decay factor
        constexpr double q_pi = decay * a0; // Decay term for pi
        constexpr double q_sigma = decay * a1; // Decay term for sigma
        double dr = term.distance; // Distance between atoms
        double n = term.rij(2) / dr; // Normalized distance component
        double v_pp_pi = -gamma0 * exp(q_pi * (1 - dr / a0)); // pi bond interaction
        double v_pp_sigma = gamma1 * exp(q_sigma * (1 - dr / a1)); // sigma bond interaction
        double fc = 1 / (1 + exp((dr - r_c) / l_c)); // Fermi cutoff
        double hop = (n * n * v_pp_sigma + (1 - n * n) * v_pp_pi) * fc; // Total hopping term
        return hop;
    }

    PrimitiveCell<complex_t> make_cell() {
        Eigen::Matrix3d lat_vec = gen_lattice_vectors(0.246, 0.246, 1.0, 90, 90, 60);
        Eigen::Vector3d origin(0.0, 0.0, 0.0);
        PrimitiveCell<complex_t> fixed_cell(2, lat_vec, origin, NM);
        fixed_cell.set_orbital_position(0, 0.0, 0.0, 0.0);
        fixed_cell.set_orbital_position(1, 1. / 3, 1. / 3, 0.0);
        fixed_cell.add_hopping(0, 0, 0, 0, 1, -2.7);
        fixed_cell.add_hopping(1, 0, 0, 1, 0, -2.7);
        fixed_cell.add_hopping(0, 1, 0, 1, 0, -2.7);
        return fixed_cell;
    }

}



int main() {
    // Create primitive cell
    auto prim_cell = make_cell();
    prim_cell.save("graphene");

    // Extend the primitive cell
    PrimitiveCell<complex_t> cell = extend_prim_cell(prim_cell, { 512,512,1 });

    // Uncomment if needed to remove specific orbitals
   //cell.remove_orbitals({524280});
   //extend_cell.trim();
   //xtend_cell.save("extend_cell");

   // Define lattice transformation matrix
   //Eigen::Matrix3d lat_frac { { 1.0, 0.0, 0.0 }, { -1.0, 2.0, 0.0 }, { 0.0, 0.0, 1.0 } };

   // Reshape and extend the cell
   //PrimitiveCell<complex_t> res_cell = reshape_prim_cell(prim_cell, lat_frac);
   //res_cell = extend_prim_cell(res_cell, { 512, 1024, 1 });

   // Apply periodic boundary conditions
    cell.apply_pbc({ true, true, false });
    //cell.save("Graphene");
    //cell.set_magnetic_field(100);
    // Uncomment to rotate the cell and save
    //res_cell.rotate(0.5 * PI);
    //res_cell.save("gnr_rot");

    // Extract hopping data
    std::tuple<std::vector<int64_t>, std::vector<int64_t>, std::vector<std::complex<double>>, std::vector<double>>
    result= cell.extract_hopping_data();
    std::vector<int64_t> hop_i = std::get<0>(result);
    std::vector<int64_t> hop_j = std::get<1>(result);
    std::vector<std::complex<double>> hop_v =
        std::get<2>(result);
    std::vector<double> dr=
        std::get<3>(result);
    // Uncomment to print hopping data
    /*
    std::cout << "hop_i: ";
    for (auto val : hop_i) std::cout << val << " ";
    std::cout << "\n";

    std::cout << "hop_j: ";
    for (auto val : hop_j) std::cout << val << " ";
    std::cout << "\n";

    std::cout << "hop_v: ";
    for (auto val : hop_v) std::cout << val << " ";
    std::cout << "\n";
    std::cout << "dr: ";
    for (size_t i = 0; i < dr.size(); i += 3) {
        std::cout << "[" << dr[i] << ", " << dr[i + 1] << ", " << dr[i + 2] << "] ";
    }
    std::cout << "\n";
    */

    // Initialize orbital energies to zero
    int64_t num_orbs = cell.get_num_orbitals();
    std::cout << "num_orbs:" << num_orbs << std::endl;
    std::vector<double> orb_eng(num_orbs, 0.0);

    // Calculate the rescale factor manually set here
    double rescale = 10.0;
    std::cout << "Rescale factor: " << rescale << std::endl;

    // Define cutoff for hopping values
    double cutoff = 1e-6;

    CSRComponents csr = build_ham_dxy_fast(orb_eng, hop_i, hop_j, hop_v, dr, cutoff);
    //saveCSRComponents(csr,"csr_data");
    // Build Hamiltonian with dx, dy terms
    auto [indptr, indices, hop, dx, dy] = build_ham_dxy_fast(orb_eng, hop_i, hop_j, hop_v, dr, cutoff);

    // Rescale hopping values
    for (auto& hop_value : hop) {
        hop_value /= rescale;
    }

    // Uncomment to print indptr
    /*
    std::cout << "indptr: ";
    for (const auto& val : indptr) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
    */

    // Parameters for the time evolution
    int n_timestep = 1024;
    int n_ran_samples = 1;
    int seed = 1314;
    double energy_range = 10.0;  // Energy range
    double time_step = M_PI / energy_range; // Time step calculation
    double time_scaled = time_step * rescale;

    // Compute Bessel function series
    std::vector<double> Bes = get_bessel(time_scaled);
    std::cout << "Bessel Series: [";
    for (size_t i = 0; i < Bes.size(); ++i) {
        std::cout << Bes[i];
        if (i < Bes.size() - 1) {
            std::cout << ", ";
        }
    }
    std::cout << "]" << std::endl;

    // Vector to store correlation function
    std::vector<std::complex<double>> corr;

    /*std::vector<int64_t> site_indices;
    // Add specific indices to site_indices
    site_indices.push_back(100);
    //site_indices.push_back(4);
    //site_indices.push_back(5);
    // Print the indices to verify
    std::cout << "Site Indices: ";
    for (const auto& index : site_indices) {
    std::cout << index << " ";
    }
    std::cout << std::endl;
    // Perform time evolution to compute density of states (DOS)
    */
    //tbplas::tbpm::tbpm_dos(Bes, indptr, indices, hop, seed, n_timestep, n_ran_samples, "output.txt", corr);
    //tbplas::tbpm::tbpm_ldos(Bes, indptr, indices, hop, seed, n_timestep, n_ran_samples, site_indices, "ldos.txt", corr);
    //tbpm::tbpm_ldos(Bes,indptr,indices,hops,seed,n_timestep,n_ran_samples,site_indices,"output.txt",corr);//checked
    //double delta = 0.02;
    //double E_range = 10.0;
    //int n_depth = 5000;
    //tbplas::tbpm::ldos_haydock(site_indices, delta,E_range,indptr,indices, hop, rescale, seed, n_depth, n_timestep, n_ran_samples, "LDOS.txt");/checked
    //TBPM with magnetic field
    //tbplas::tbpm::tbpm_dos(Bes, indptr, indices, hop, seed, n_timestep, n_ran_samples, "output_dos.txt", corr);//checked 
    //TBPM AC conductivity
    double Fermi_precision = 1.0e-12;
    double KB = 8.617333262e-5;    
    double T = 300; // Temperature
    double beta = rescale * 1 / (KB * T);
    double mu = 0;
    int nr_Fermi = std::pow(2, 15);
    Eigen::MatrixXcd corr_ac;
    //类型切换
     std::vector<int64_t> d_s_indptr, d_s_indices;
     for (auto item : indptr)
         d_s_indptr.push_back(item);
	 for (auto item : indices)
         d_s_indices.push_back(item);

     //保留下参数，进行校验
     QString curPath = QDir::currentPath();
     QString filepath = curPath.append("\\tbpm.input");
     QSettings settings(filepath,QSettings::IniFormat);
     
     settings.setValue("tbpm_accond/nBes", QString::number(Bes.size()));
     QString besStr;
     for (size_t i = 0; i < Bes.size(); i++){
         if (!besStr.isEmpty())
             besStr.append("|");
         besStr.append(QString::number(Bes[i], 'f', 15));
     }
     settings.setValue("Bes", besStr);

     settings.setValue("tbpm_accond/beta", QString::number(beta, 'f', 15));
     settings.setValue("tbpm_accond/mu", QString::number(mu, 'f', 15));

     besStr.clear();
     settings.setValue("tbpm_accond/n_indptr", QString::number(d_s_indptr.size()));
     for (size_t i = 0; i < d_s_indptr.size(); i++) {
         if (!besStr.isEmpty())
             besStr.append("|");
         besStr.append(QString::number(d_s_indptr[i]));
     }
     settings.setValue("s_indptr", besStr);

     besStr.clear();
     settings.setValue("tbpm_accond/n_indices", QString::number(d_s_indices.size()));
     for (size_t i = 0; i < d_s_indices.size(); i++) {
         if (!besStr.isEmpty())
            besStr.append("|");
         besStr.append(QString::number(d_s_indices[i]));
     }
     settings.setValue("s_indices", besStr);
     
     besStr.clear();
     settings.setValue("tbpm_accond/n_hop", QString::number(hop.size()));
     for (size_t i = 0; i < hop.size(); i++) {
         if (!besStr.isEmpty())
            besStr.append("|");
         besStr.append(QString::number(hop[i].real(), 'f', 15).append("~").append(
                       QString::number(hop[i].imag(), 'f', 15)
         ));
     }
     settings.setValue("s_hop", besStr);
     settings.setValue("tbpm_accond/H_rescale", QString::number(rescale, 'f', 15));

     besStr.clear();
     settings.setValue("tbpm_accond/n_dy", QString::number(dy.size()));
     for (size_t i = 0; i < dy.size(); i++) {
         if (!besStr.isEmpty())
            besStr.append("|");
         besStr.append(QString::number(dy[i], 'f', 15));
     }
     settings.setValue("n_dy", besStr);

     besStr.clear();
     settings.setValue("tbpm_accond/n_dx", QString::number(dx.size()));
     for (size_t i = 0; i < dx.size(); i++) {
         if (!besStr.isEmpty())
            besStr.append("|");
         besStr.append(QString::number(dx[i], 'f', 15));
     }
     settings.setValue("n_dx", besStr);

     settings.setValue("tbpm_accond/seed", QString::number(seed));
     settings.setValue("tbpm_accond/n_ran_samples", QString::number(n_ran_samples, 'f', 15));
     settings.setValue("tbpm_accond/nr_Fermi", QString::number(nr_Fermi, 'f', 15));
     settings.setValue("tbpm_accond/Fermi_precision", QString::number(Fermi_precision, 'f', 15));
     settings.setValue("tbpm_accond/output_filename", "AC.txt");
     settings.setValue("tbpm_accond/n_timestep", QString::number(n_timestep));
     settings.sync();


     tbplas::tbpm::tbpm_accond(Bes, beta, mu,
         d_s_indptr, d_s_indices, hop,
         rescale, dx, dy,
         seed, n_timestep,
         n_ran_samples, nr_Fermi, Fermi_precision,
         "AC.txt", corr_ac); //Calculate AC properply

     //corr 4*n_timestep
     for (size_t i = 0; i < n_timestep; i++) {
         QString key("corr/");
         key.append(QString::number(i));
         QString rowData;
         for (auto item: corr_ac.row(i))
         {
             if (!rowData.isEmpty())
                rowData.append("|");
             rowData.append(QString::number(item.real()).append("~").append(
                 QString::number(item.imag())));
         }
         settings.setValue(key, rowData);
     }
    
     settings.sync();
    return 0;
}