// auto_detect_type — infiere ColumnType muestreando celdas de una columna.
// Promovido del playground tables (issue 0081-F). Pura — sin I/O ni estado.

#include "core/auto_detect_type.h"

#include <cstdlib>
#include <cstring>

namespace data_table {

bool is_bool_text(const char* s) {
    return std::strcmp(s, "true") == 0 || std::strcmp(s, "false") == 0;
}

bool is_date_iso(const char* s) {
    // YYYY-MM-DD minimo
    if (std::strlen(s) < 10) return false;
    auto d = [](char c){ return c >= '0' && c <= '9'; };
    return d(s[0]) && d(s[1]) && d(s[2]) && d(s[3]) && s[4] == '-' &&
           d(s[5]) && d(s[6]) && s[7] == '-' && d(s[8]) && d(s[9]);
}

bool is_json_text(const char* s) {
    while (*s == ' ' || *s == '\t') ++s;
    return *s == '{' || *s == '[';
}

bool is_integer_text(const char* s) {
    if (!*s) return false;
    if (*s == '-' || *s == '+') ++s;
    if (!*s) return false;
    for (; *s; ++s) if (*s < '0' || *s > '9') return false;
    return true;
}

bool parse_number(const char* s, double& out) {
    if (!s || !*s) return false;
    char* end = nullptr;
    double v = std::strtod(s, &end);
    if (end == s) return false;
    while (*end == ' ' || *end == '\t') end++;
    if (*end != '\0') return false;
    out = v;
    return true;
}

ColumnType auto_detect_type(const char* const* cells, int rows, int cols,
                            int col, int sample_n)
{
    if (col < 0 || col >= cols) return ColumnType::String;
    int n_total = 0, n_int = 0, n_float = 0, n_bool = 0, n_date = 0, n_json = 0;
    for (int r = 0; r < rows && n_total < sample_n; ++r) {
        const char* c = cells[r * cols + col];
        if (!c || !*c) continue;
        n_total++;
        if (is_bool_text(c))      { n_bool++; continue; }
        if (is_date_iso(c))       { n_date++; continue; }
        if (is_json_text(c))      { n_json++; continue; }
        double v;
        if (parse_number(c, v)) {
            if (is_integer_text(c)) n_int++;
            else                    n_float++;
            continue;
        }
        // string puro: no se acumula en ningun tipo -> garantiza fallthrough a String
    }
    if (n_total == 0)                return ColumnType::String;
    if (n_bool == n_total)           return ColumnType::Bool;
    if (n_date == n_total)           return ColumnType::Date;
    if (n_json == n_total)           return ColumnType::Json;
    if (n_int + n_float == n_total)  return (n_float > 0) ? ColumnType::Float : ColumnType::Int;
    return ColumnType::String;
}

} // namespace data_table
