// Qué orden sale al comparar bytes, y por qué un std::string no se confunde con el signo de char.
// Uso: byte_order archivo_de_terminos
#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <iostream>
#include <limits>
#include <string>
#include <vector>

#include "lab/terms_io.h"

namespace {

// Compara char por char. Depende de si char tiene signo en esta máquina.
bool less_by_char(const std::string& a, const std::string& b) {
    std::size_t common = std::min(a.size(), b.size());
    for (std::size_t i = 0; i < common; i++) {
        if (a[i] != b[i]) {
            return a[i] < b[i];
        }
    }
    return a.size() < b.size();
}

void print_words(const char* label, const std::vector<std::string>& words) {
    std::cout << label << ":";
    for (const std::string& word : words) {
        std::cout << " " << word;
    }
    std::cout << "\n";
}

void print_bytes(const std::string& word) {
    std::cout << word << " =";
    for (char c : word) {
        std::printf(" %02x", static_cast<unsigned>(static_cast<unsigned char>(c)));
    }
    std::cout << ", size() = " << word.size() << "\n";
}

// Busca revisando todo el archivo: es lento, y por eso es confiable para este ejemplo.
void scan_prefix(const std::vector<Term>& sorted_terms, const std::string& prefix) {
    std::size_t first = sorted_terms.size();
    std::size_t last = 0;
    std::size_t count = 0;
    for (std::size_t i = 0; i < sorted_terms.size(); i++) {
        if (sorted_terms[i].text.starts_with(prefix)) {
            first = std::min(first, i);
            last = i + 1;
            count++;
        }
    }
    std::printf("%-4s %5zu términos en [%zu, %zu): de %s a %s\n", prefix.c_str(), count, first, last,
                sorted_terms[first].text.c_str(), sorted_terms[last - 1].text.c_str());
}

}  // namespace

int main(int argc, char** argv) {
    if (argc != 2) {
        std::cerr << "uso: byte_order archivo_de_terminos\n";
        return 2;
    }
    print_bytes("a");
    print_bytes("á");
    print_bytes("ñ");
    print_bytes("z");

    std::vector<std::string> words = {"zorro", "cámara", "caña", "ñandú", "cazar", "árbol", "cama"};
    std::cout << "char con signo: " << (std::numeric_limits<char>::is_signed ? "sí" : "no") << "\n";
    std::sort(words.begin(), words.end());
    print_words("con std::string", words);
    std::sort(words.begin(), words.end(), less_by_char);
    print_words("char por char ", words);

    std::vector<Term> terms;
    if (!load_terms(argv[1], terms)) {
        std::cerr << "no se pudo leer " << argv[1] << "\n";
        return 1;
    }
    std::sort(terms.begin(), terms.end(), [](const Term& a, const Term& b) { return a.text < b.text; });
    for (const char* prefix : {"a", "á", "ca", "cá", "cañ", "z", "ñ"}) {
        scan_prefix(terms, prefix);
    }
    std::string wanted_low = "ca";
    std::string wanted_high = "cazzzz";
    std::size_t naive = 0;
    for (const Term& term : terms) {
        if (term.text >= wanted_low && term.text <= wanted_high) {
            naive++;
        }
    }
    std::printf("entre ca y cazzzz: %zu términos\n", naive);
    return 0;
}
