#pragma once

#include <cstdint>
#include <vector>

namespace contextra {

constexpr const char* kDetsTensorName = "dets";
constexpr const char* kLabelsTensorName = "labels";
constexpr uint32_t kBoxWidth = 4;
constexpr uint32_t kModelClassCount = 91;
constexpr uint32_t kForegroundClassCount = 80;

struct TensorContract {
    bool detsFp32;
    bool labelsFp32;
    std::vector<uint32_t> detsDims;
    std::vector<uint32_t> labelsDims;
    uint32_t runtimeBatchSize;
};

inline bool validateTensorContract(const TensorContract& contract)
{
    if (!contract.detsFp32 || !contract.labelsFp32) {
        return false;
    }
    if (contract.detsDims.size() != 3 || contract.labelsDims.size() != 3) {
        return false;
    }
    const uint32_t batch = contract.detsDims[0];
    const uint32_t queries = contract.detsDims[1];
    return batch > 0 && queries > 0 && batch == contract.runtimeBatchSize
        && contract.labelsDims[0] == batch && contract.labelsDims[1] == queries
        && contract.detsDims[2] == kBoxWidth
        && contract.labelsDims[2] == kModelClassCount;
}

inline int canonicalClassId(uint32_t modelClassId)
{
    // MODELCONTRACT-01: COCO sparse slot을 명시적으로 dense class로 매핑한다.
    constexpr uint32_t slots[] = {
        1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,
        22,23,24,25,27,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,
        46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,
        67,70,72,73,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90
    };
    for (uint32_t i = 0; i < kForegroundClassCount; ++i) {
        if (slots[i] == modelClassId) return static_cast<int>(i);
    }
    return -1;
}

inline bool validateFireTensorContract(const TensorContract& c)
{
    return c.detsFp32 && c.labelsFp32 && c.runtimeBatchSize == 1
        && c.detsDims == std::vector<uint32_t>{1,300,4}
        && c.labelsDims == std::vector<uint32_t>{1,300,3};
}

}  // namespace contextra
