/*
     Description: apply bqsr过程中对sam的一些修改函数

     Copyright : All right reserved by ICT

     Author : Zhang Zhonghai
     Date : 2026/01/02
*/
#pragma once

#include <htslib/sam.h>
#include <spdlog/spdlog.h>

struct ReadUtils {
    // sam/bam文件中的quality score要在原来的quality上加33，应该是映射到字符区，方便用字母表示
    // htslib解析之后已经减掉了，就是真实的质量分数
    static constexpr int QUALITY_SCORE_ADD_IN_FILE = 33;
    /**
     * Resets the quality scores of the reads to the orginal (pre-BQSR) ones.
     */
    static void resetOriginalBaseQualities(bam1_t *b) {
        uint8_t* oq = bam_aux_get(b, "OQ");
        char* oqVal = nullptr;
        if (oq)
            oqVal = bam_aux2Z(oq);
        int crg = 0;
        if (oqVal == nullptr) {
        } else {
            uint8_t* quals = bam_get_qual(b);
            for (int i = 0; i < b->core.l_qseq; ++i) {
                quals[i] = oqVal[i] - QUALITY_SCORE_ADD_IN_FILE; // 要减掉33
            }
        }
    }

    // get read group id
    static const char* getReadGroupId(bam1_t *b) {
        uint8_t* rgStr = bam_aux_get(b, "RG");
        char* rgVal = nullptr;
        if (rgStr)
            rgVal = bam_aux2Z(rgStr);
        return rgVal;
    }

    // 将当前quals保存在OQ tag中 （如果当前read不存在OQ tag的情况下）
    static void setOriginalBaseQualsIfNoOQ(bam1_t *b) {
        uint8_t* tagData = bam_aux_get(b, "OQ");
        if (tagData)
            return;
        char* tagVal = nullptr;
        const char* oldQual = (char*)bam_get_qual(b);
        string qual(b->core.l_qseq + 1, '\0');
        for (int i = 0; i < qual.size() - 1; ++i) {
            qual[i] = oldQual[i] + QUALITY_SCORE_ADD_IN_FILE;
        }
        // bam_aux_append 最后一个字符必须是'\0'
        if (bam_aux_append(b, "OQ", 'Z', qual.size(), (const uint8_t*)qual.c_str()) != 0) {
            spdlog::error("Add OQ (original quality score) tag failed. ");
        }
    }

    // 移除给定的tag
    static void removeAttribute(bam1_t *b, const string &tag) {
        uint8_t* tagData = bam_aux_get(b, "OQ");
        if (!tagData)
            return;
        if (bam_aux_remove(b, tagData) == nullptr) {
            spdlog::error("Remove tag {} failed. ", tag);
        }
    }
};