#include <random>

#include "testlib.h"

struct Test {
    std::string s;
};

std::ostream& operator<<(std::ostream& out, const Test& m) {
    return out << m.s;
}

struct Multitest {
    std::vector<Test> tests;
};

std::ostream& operator<<(std::ostream& out, const Multitest& m) {
    out << m.tests.size() << '\n';
    for (const Test& test : m.tests)
        out << test << '\n';
    return out;
}

Multitest generate_smallest() {
    const size_t t = opt<size_t>("t");
    const size_t max_s = opt<size_t>("max_s");
    Multitest m;
    size_t s = 0;
    for (size_t n = 1; m.tests.size() < t && s < max_s; ++n) {
        size_t po7 = 1;
        for (size_t i = 0; i < n; ++i)
            po7 *= 7;
        for (size_t mask = 0; mask < po7 && m.tests.size() < t; ++mask) {
            Test test;
            size_t temp = mask;
            for (size_t i = 0; i < n; ++i) {
                test.s += 'A' + temp % 7;
                temp /= 7;
            }
            std::reverse(test.s.begin(), test.s.end());

            s += test.s.size();
            if (s > max_s)
                break;
            m.tests.push_back(test);
        }
    }
    return m;
}

std::vector<size_t> divide_with_positive_addends(size_t sum, size_t addends) {
    std::vector<bool> b(sum - 1);
    for (size_t i = 0; i < addends - 1; ++i)
        b[i] = true;
    shuffle(b.begin(), b.end());
    std::vector<size_t> ans(1, 1);
    for (bool c : b)
        if (c)
            ans.push_back(1);
        else
            ++ans.back();
    return ans;
}

Multitest generate_random() {
    const size_t t = opt<size_t>("t");
    const size_t max_s = opt<size_t>("max_s");
    std::vector<size_t> sizes = divide_with_positive_addends(max_s, t);
    Multitest m{
        .tests = std::vector<Test>(t),
    };
    for (size_t i = 0; i < t; ++i)
        m.tests[i].s.resize(sizes[i], ' ');
    for (Test& test : m.tests)
        for (char& c : test.s)
            c = rnd.next('A', 'G');
    return m;
}

Multitest generate_random_tight() {
    return {};
}

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);
    std::string type = opt<std::string>("type");
    Multitest multitest;
    if (type == "smallest")
        multitest = generate_smallest();
    else if (type == "random")
        multitest = generate_random();
    else if (type == "random_tight")
        multitest = generate_random_tight();
    std::cout << multitest;
}
