/*
     Description: 生成数据报表

     Copyright : All right reserved by ICT

     Author : Zhang Zhonghai
     Date : 2025/12/27
*/
#pragma once

#include <string>
#include <vector>
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <sstream>
#include <iomanip>

#include <spdlog/spdlog.h>

using std::string;
using std::stringstream;
using std::vector;

#define REPORT_HEADER_VERSION "#:GATKReport.v1.1:5"

struct ReportUtil {
    static string ToString(const bool val) { return val ? "true" : "false"; }
    static string ToString(const char val) {
        string s = "";
        s += val;
        // spdlog::info("char: {}, str: {}", val, s);
        return s;
    }
    static string ToString(const string& val) { return val == "" ? "null" : val; }
    static string ToString(const double val, int precise) {
        stringstream ss;
        ss << std::fixed << std::setprecision(precise) << val;
        return ss.str();
    }
    template<typename T>
    static string ToString(const T val) { return std::to_string(val); }
};

struct ReportTable {
    // 静态数据

    static const string COULD_NOT_READ_HEADER;
    static const string COULD_NOT_READ_COLUMN_NAMES;
    static const string COULD_NOT_READ_DATA_LINE;
    static const string COULD_NOT_READ_EMPTY_LINE;
    static const string OLD_GATK_TABLE_VERSION;
    static const char* TABLE_PREFIX;

    // 数据表排序方式
    // 好像目前都是按照SORT_BY_COLUMN排序的，这个排序是以此按照每一个cloumn内的所有行数据进行排序，从左到右，目的还是排列行的数据
    // SORT_BY_ROW应该就是按照row id排序的
    enum struct Sorting { SORT_BY_ROW, SORT_BY_COLUMN, DO_NOT_SORT };
    // 数据类型
    enum struct DataType {
        /**
         * The null type should not be used.
         */
        NullType,
        /**
         * The default value when a format string is not present
         */
        Unknown,
        /**
         * Used for boolean values. Will display as true or false in the table.
         */
        Boolean,
        /**
         * Used for char values. Will display as a char so use printable values!
         */
        Character,
        /**
         * Used for float and double values. Will output a decimal with format %.8f unless otherwise specified.
         */
        Decimal,
        /**
         * Used for int, byte, short, and long values. Will display the full number by default.
         */
        Integer,
        /**
         * Used for string values. Displays the string itself.
         */
        String
    };
    // 列类型
    struct Column {
        // 只有column内容全是数字时(或者nan，inf，null这些)，可以右对齐，剩下的字符或者字符串只能左对齐
        enum struct Alignment {LEFT, RIGHT};
        string columnName;
        string format;
        DataType dataType;
        Alignment alignment = Alignment::RIGHT;
        int maxWidth = 0;

        Column() {}
        Column(const string& name) : Column(name, "%s") {}
        Column(const string& name, const string& _format) : Column(name, _format, DataType::String) {}
        Column(const string& name, const string& _format, const DataType _dataType) : Column(name, _format, _dataType, Alignment::RIGHT) {}
        Column(const string& name, const string& _format, const DataType _dataType, const Alignment align) { init(name, _format, _dataType, align); }

        void init(const string& name, const string &_format, const DataType _dataType, const Alignment align) {
            columnName = name;
            format = _format;
            dataType = _dataType;
            alignment = align;
            maxWidth = name.size();
            updateFormat(*this); // format和datatype要一致
        }

        void updateMaxWidth(const string &value) {
            if (!value.empty()) {
                maxWidth = std::max(maxWidth, (int)value.size());
            }
        }

        // 根据col的format更新一下对齐等信息
        static void updateFormat(Column &col) {
            if (col.format == "") {
                col.dataType = DataType::Unknown;
                col.format = "%s";
            } else if (col.format.find('s') != string::npos) {
                col.dataType = DataType::String;
            } else if (col.format.find('d') != string::npos) {
                col.dataType = DataType::Integer;
            } else if (col.format.find('f') != string::npos) {
                col.dataType = DataType::Decimal;
            }
            // spdlog::info("type: {}, align {}", col.dataType == DataType::Integer, col.alignment == Alignment::LEFT);
            // 只有数字可以右对齐
            if (col.dataType != DataType::Decimal && col.dataType != DataType::Integer)
                col.alignment = Column::Alignment::LEFT;
        }

        string getNameFormat() { return "%-" + std::to_string(maxWidth) + "s";}

        string getValueFormat() {
            string align = alignment == Alignment::LEFT ? "-" : "";
            return "%" + align + std::to_string(maxWidth) + "s"; // 因为所有值都转换成string类型了
        }
    };

    using RowData = vector<string>; // 每一行的数据

    string tableName;        // 数据表名称
    string tableDescription; // 数据表描述
    Sorting sortingWay; // 排序方式
    vector<Column> columnInfo; // 包含数据表的所有列信息
    vector<RowData> underlyingData; // 保存数据表所有数据
    vector<size_t> idxArr; // 保存data的索引，用来排序

    ReportTable() {}
    ReportTable(const string& _tableName) : ReportTable(_tableName, "") {}
    ReportTable(const string& _tableName, const string& _tableDescription) : ReportTable(_tableName, _tableDescription, Sorting::SORT_BY_COLUMN) {}
    ReportTable(const string& _tableName, const string& _tableDescription, const Sorting sorting) { init(_tableName, _tableDescription, sorting); }

    // 初始化
    void init(const string& _tableName, const string& _tableDescription, const Sorting sorting) {
        tableName = _tableName;
        tableDescription = _tableDescription;
        sortingWay = sorting;
    }

    // 添加column
    void addColumn(Column col) {
        // spdlog::info("col align: {}", col.alignment == Column::Alignment::RIGHT);
        Column::updateFormat(col);
        columnInfo.push_back(col);
    }

    void addRowData(const RowData &dat) {
        assert(dat.size() == columnInfo.size());
        idxArr.push_back(underlyingData.size());
        underlyingData.push_back(dat);
        for (int i = 0; i < dat.size(); ++i) {
            columnInfo[i].updateMaxWidth(dat[i]);
        }
    }

    void sort() {
        std::sort(idxArr.begin(), idxArr.end(), [&](size_t a, size_t b) { 
            auto& r1 = underlyingData[a];
            auto& r2 = underlyingData[b];
            for (int i = 0; i < r1.size(); ++i) {
                if (r1[i] != r2[i]) {
                    if (columnInfo[i].format.find('d') != string::npos) // 或者用datatype来判断
                        return std::stoll(r1[i]) < std::stoll(r2[i]);
                    else if (columnInfo[i].format.find('f') != string::npos) {
                        return std::stod(r1[i]) < std::stod(r2[i]);
                    } else {
                        return r1[i] < r2[i];
                    }
                }
            }
            return a < b;
        });
    }

    // 输出
    void write(FILE *fpout) {
        // 表头，列数:行数:列格式
        fprintf(fpout, "#:%s:%d:%d:", TABLE_PREFIX, (int)columnInfo.size(), (int)underlyingData.size());
        for (auto& col : columnInfo) fprintf(fpout, "%s:", col.format.c_str());
        fprintf(fpout, ";\n");
        // 表的说明
        fprintf(fpout, "#:%s:%s:%s\n", TABLE_PREFIX, tableName.c_str(), tableDescription.c_str());
        // 列名称
        bool needPadding = false;
        for (auto& col : columnInfo) {
            if (needPadding)
                fprintf(fpout, "  ");
            needPadding = true;
            fprintf(fpout, col.getNameFormat().c_str(), col.columnName.c_str());
        }
        fprintf(fpout, "\n");
        // 表的所有行数据
        // 先排个序
        sort();
        for (auto idx : idxArr) {
            auto &row = underlyingData[idx];
            bool needPadding = false;
            for (int i = 0; i < row.size(); ++i) {
                if (needPadding)
                    fprintf(fpout, "  ");
                needPadding = true;
                fprintf(fpout, columnInfo[i].getValueFormat().c_str(), row[i].c_str());
            }
            fprintf(fpout, "\n");
        }
        fprintf(fpout, "\n");
    }
};

/*
// 输出参数相关的数据
struct ArgReportTable : ReportTable {
    using ReportTable::ReportTable;
};

// 输出quantized quality相关的数据
struct QuantReportTable : ReportTable {

};

// 输出协变量相关的数据
struct CovariateReportTable : ReportTable {

};
*/