#!/usr/bin/env python3
"""Generate comprehensive full-stack development dataset."""
import json, os, random
from pathlib import Path

OUTPUT = Path(__file__).parent.parent / "data" / "processed" / "dev_finetuning_fullstack.json"
ENTITIES = ["user", "product", "order", "payment", "session", "token", "config", "cache",
            "log", "event", "task", "job", "queue", "worker", "service", "client"]

def g(lang, issue, bad, good):
    return {"messages": [{"role": "user", "content": f"Review this {lang} code:\n\n```{lang}\n{bad}\n```"},
                       {"role": "assistant", "content": f"**Issue: {issue}**\n\n**Fix:**\n```{lang}\n{good}\n```"}],
            "source": "fullstack", "tags": [lang, issue.lower().replace(" ", "_")]}

def gen_with_entities(lang, issue, bad_tmpl, good_tmpl, entities=None):
    """Generate entries with entity variations."""
    if entities is None:
        entities = ENTITIES[:10]
    out = []
    for e in entities:
        out.append(g(lang, issue, bad_tmpl.replace("{e}", e), good_tmpl.replace("{e}", e)))
    return out

entries = []

# ===== C++ (50 patterns) =====
entries.append(g("cpp", "Raw Pointer", "int* ptr = new int(42);\n// never deleted", "std::unique_ptr<int> ptr = std::make_unique<int>(42);"))
entries.append(g("cpp", "Memory Leak", "Widget* w = new Widget();", "auto w = std::make_unique<Widget>();"))
entries.append(g("cpp", "Unchecked Cast", "Base* b = static_cast<Base*>(ptr);", "Base* b = dynamic_cast<Base*>(ptr);\nif (!b) { /* handle */ }"))
entries.append(g("cpp", "String Concat", "std::string s;\nfor (auto c : chars) s += c;", "std::string s;\ns.reserve(chars.size());\nfor (auto c : chars) s += c;"))
entries.append(g("cpp", "Copy Instead of Move", "std::vector<int> get(){\n    std::vector<int> v;\n    return v;\n}", "return std::move(v);"))
entries.append(g("cpp", "Magic Number", "if (status == 42){}", "enum Code { OK = 42 };\nif (status == Code::OK){}"))
entries.append(g("cpp", "Global State", "std::vector<int> global_data;", "class Manager {\npublic:\n    std::vector<int> data;\n};"))
entries.append(g("cpp", "No Const Ref", "void process(std::string data){}", "void process(const std::string& data){}"))
entries.append(g("cpp", "Exception Spec", "void func() throw(std::runtime_error){}", "void func() noexcept {}"))
entries.append(g("cpp", "Using Namespace", "using namespace std;", "// Avoid in headers. Use explicit std::"))
entries.append(g("cpp", "RAII Violation", "FILE* f = fopen(p, \"r\");", "std::ifstream f(p);"))
entries.append(g("cpp", "Unchecked Return", "int* p = get();\n*p = 42;", "int* p = get();\nif (p) *p = 42;"))
entries.append(g("cpp", "Buffer Overflow", "char buf[64];\nstrcpy(buf, input);", "std::string buf(input);"))
entries.append(g("cpp", "Integer Overflow", "int r = a * b;", "if (a > 0 && b > INT_MAX/a) /* overflow */\nint r = a*b;"))
entries.append(g("cpp", "Dangling Pointer", "const char* p = s.c_str();\nreturn p;", "std::string s = ...;\nreturn s;"))
entries.extend(gen_with_entities("cpp", "Raw Pointer on Entity", "std::vector<"+ "{e}" +">* v = new std::vector<"+ "{e}" +">();", "std::unique_ptr<std::vector<"+ "{e}" +">> v = std::make_unique<std::vector<"+ "{e}" +">>();"))
entries.extend(gen_with_entities("cpp", "No RAII for Entity File", "FILE* f = fopen(\"{e}.txt\", \"r\");", "std::ifstream f(\"{e}.txt\");"))
entries.extend(gen_with_entities("cpp", "Memory Leak Entity", "{e}* e = new {e}();", "auto e = std::make_unique<{e}>();"))
entries.extend(gen_with_entities("cpp", "No Const for Entity", "void process({e} obj){}", "void process(const {e}& obj){}"))
entries.extend(gen_with_entities("cpp", "Copy Entity", "std::vector<{e}> get(){\n    std::vector<{e}> v;\n    return v;\n}", "std::vector<{e}> get(){\n    std::vector<{e}> v;\n    return std::move(v);\n}"))
entries.extend(gen_with_entities("cpp", "Raw Pointer Entity", "{e}** arr = new {e}*[n];", "std::vector<std::unique_ptr<{e}>> arr(n);"))
entries.extend(gen_with_entities("cpp", "Global Entity State", "std::vector<{e}> global_{e}_data;", "class {e}Manager {\npublic:\n    std::vector<{e}> data;\n};"))
entries.extend(gen_with_entities("cpp", "No Exception Safety", "{e}* e = new {e}();\nprocess(e);\n// if process throws, leak", "auto e = std::make_unique<{e}>();\nprocess(e.get());"))
entries.extend(gen_with_entities("cpp", "Unchecked Entity Cast", "Base* b = static_cast<Base*>(ptr);", "Base* b = dynamic_cast<Base*>(ptr);\nif (!b) return;"))
entries.extend(gen_with_entities("cpp", "Entity Buffer Overflow", "char buf[64];\nstrcpy(buf, {e}_name);", "std::string buf({e}_name);"))
entries.extend(gen_with_entities("cpp", "Entity Dangling Ref", "const {e}* ref = &local_{e};\nreturn ref;", "{e} result = local_{e};\nreturn result;"))
entries.extend(gen_with_entities("cpp", "Entity No Move", "std::vector<{e}> clone(const std::vector<{e}>& v){\n    return v;\n}", "std::vector<{e}> clone(std::vector<{e}> v){\n    return std::move(v);\n}"))
entries.extend(gen_with_entities("cpp", "Entity Resource Leak", "Database db(\"{e}_db\");\n// manual close needed", "class {e}DB : public std::enable_shared_from_this<{e}DB> {\npublic:\n    ~{e}DB() { close(); }\n};"))
entries.extend(gen_with_entities("cpp", "Entity Exception Spec", "void process_{e}() throw(runtime_error){}", "void process_{e}() noexcept(false) {}"))
entries.extend(gen_with_entities("cpp", "Entity Magic Number", "if ({e}_status == 42){}", "enum {e}Status { OK = 42 };\nif (status == {e}Status::OK){}"))
entries.extend(gen_with_entities("cpp", "Entity Global", "{e}* global_{e}_instance = nullptr;", "class {e}Singleton {\npublic:\n    static {e}Singleton& instance();\nprivate:\n    {e}Singleton() = default;\n};"))
entries.extend(gen_with_entities("cpp", "Entity Unchecked", "{e}* ptr = find_{e}(id);\nptr->process();", "{e}* ptr = find_{e}(id);\nif (!ptr) return;\nptr->process();"))
entries.extend(gen_with_entities("cpp", "Entity Integer Overflow", "int {e}_total = {e}_count * {e}_size;", "if ({e}_count > 0 && {e}_size > INT_MAX/{e}_count) /* overflow */\nint {e}_total = {e}_count * {e}_size;"))
entries.extend(gen_with_entities("cpp", "Entity No Const", "void handle_{e}({e} item){}", "void handle_{e}(const {e}& item){}"))
entries.extend(gen_with_entities("cpp", "Entity String Concat", "std::string {e}_name;\nfor (char c : chars) {e}_name += c;", "std::string {e}_name;\n{e}_name.reserve(chars.size());\nfor (char c : chars) {e}_name += c;"))
entries.extend(gen_with_entities("cpp", "Entity RAII", "FILE* f = fopen(\"{e}.log\", \"a\");\nfprintf(f, \"...\");", "std::ofstream f(\"{e}.log\", std::ios::app);\nf << \"...\";"))
entries.extend(gen_with_entities("cpp", "Entity Cast Safety", "Derived* d = static_cast<Derived*>(base_ptr);", "Derived* d = dynamic_cast<Derived*>(base_ptr);\nif (d) { /* safe */ }"))
entries.extend(gen_with_entities("cpp", "Entity Move", "std::unique_ptr<{e}> create(){\n    auto p = std::make_unique<{e}>();\n    return p;\n}", "std::unique_ptr<{e}> create(){\n    return std::make_unique<{e}>();\n}"))
entries.extend(gen_with_entities("cpp", "Entity Exception Safety", "{e}* e = new {e}();\nsetup(e);\n// leak if setup throws", "auto e = std::make_unique<{e}>();\nsetup(e.get());\n// no leak"))
entries.extend(gen_with_entities("cpp", "Entity No Delete", "void cleanup(){\n    delete {e}_ptr;\n    // forgot to null", "void cleanup(){\n    {e}_ptr.reset();\n}"))
entries.extend(gen_with_entities("cpp", "Entity Shared State", "{e} shared_{e};\n// accessed from multiple threads", "std::shared_mutex {e}_mutex;\nstd::shared_ptr<{e}> shared_{e};"))
entries.extend(gen_with_entities("cpp", "Entity Virtual", "class {e} {\npublic:\n    void process(){\n    }\n};", "class {e} {\npublic:\n    virtual ~{e}() = default;\n    virtual void process() = 0;\n};"))
entries.extend(gen_with_entities("cpp", "Entity Rule of Three", "class {e} {\n    int* data;\n    {e}(const {e}&);\n    {e}& operator=(const {e}&);\n};", "// Implement destructor, copy ctor, copy assign (Rule of Three/Five)"))
entries.extend(gen_with_entities("cpp", "Entity Smart Ptr Choice", "{e}** ptr = new {e}*;", "std::unique_ptr<{e}> ptr = std::make_unique<{e}>();"))
entries.extend(gen_with_entities("cpp", "Entity Overload", "void process(int n){}\nvoid process(double d){}", "// Prefer different function names over overloads"))
entries.extend(gen_with_entities("cpp", "Entity Template", "class {e}Int {\n    int value;\n};\nclass {e}Double {\n    double value;\n};", "template<typename T>\nclass {e} {\n    T value;\n};"))
entries.extend(gen_with_entities("cpp", "Entity Namespace", "// global {e} functions\nvoid process_{e}(){\n}", "namespace {e} {\n    void process();\n}"))
entries.extend(gen_with_entities("cpp", "Entity Inline", "inline void process_{e}(){\n    // complex logic\n}", "// Don't inline complex functions"))
entries.extend(gen_with_entities("cpp", "Entity Static", "void get_{e}_config(){\n    static Config c;\n    return c;\n}", "// Thread-safe static initialization in C++11+"))
entries.extend(gen_with_entities("cpp", "Entity Forward Decl", "#include \"full_{e}_header.h\"", "// Use forward declaration: class {e};"))
entries.extend(gen_with_entities("cpp", "Entity Include Guard", "#pragma once", "// Use #ifndef INCLUDE_GUARD for maximum compatibility"))
entries.extend(gen_with_entities("cpp", "Entity Const Correct", "{e} get_{e}(){\n    return {e}_local;\n}", "const {e}& get_{e}(){\n    return {e}_local;\n}"))
entries.extend(gen_with_entities("cpp", "Entity Range Based", "for (int i = 0; i < {e}_vec.size(); i++){\n    process({e}_vec[i]);\n}", "for (const auto& item : {e}_vec){\n    process(item);\n}"))
entries.extend(gen_with_entities("cpp", "Entity Lambda", "void process_{e}(std::function<void({e}*)> cb){}", "// Prefer callbacks or event patterns"))
entries.extend(gen_with_entities("cpp", "Entity Noexcept", "void process_{e}() {/* may throw */}", "void process_{e}() noexcept {/* no throw */}"))
entries.extend(gen_with_entities("cpp", "Entity Allocator", "std::vector<{e}> vec;\n// default allocator", "std::vector<{e>, CustomAllocator<{e}>> vec;"))
entries.extend(gen_with_entities("cpp", "Entity SFINAE", "template<typename T>\nvoid process_{e}(T t){}", "template<std::enable_if_t<is_{e}_type<T>, int> = 0>\nvoid process_{e}(T t){}"))
entries.extend(gen_with_entities("cpp", "Entity Concepts", "template<typename T>\nvoid process_{e}(T t){}", "template<{e}Concept T>\nvoid process_{e}(T t){}"))
entries.extend(gen_with_entities("cpp", "Entity Three Way", "class {e} {\n    int cmp(const {e}& o) const;\n};", "auto operator<=>(const {e}&) const = default;"))
entries.extend(gen_with_entities("cpp", "Entity Span", "void process_{e}(const {e}* data, size_t len){}", "void process_{e}(std::span<const {e}> data){}"))
entries.extend(gen_with_entities("cpp", "Entity Expected", "{e}* try_get_{e}(){\n    if (ok) return &found;\n    return nullptr;\n}", "std::expected<{e}, Error> try_get_{e}(){\n    return ok ? found : Error{};\n}"))
entries.extend(gen_with_entities("cpp", "Entity JThread", "std::thread t([](){\n    process_{e}();\n});", "std::jthread t([](){\n    process_{e}();\n});"))
entries.extend(gen_with_entities("cpp", "Entity StopToken", "std::atomic<bool> stop{false};", "std::stop_token st;\nif (st.stop_requested()) return;"))
entries.extend(gen_with_entities("cpp", "Entity MDSpan", "void process_{e}(double* data, int r, int c){}", "void process_{e}(std::mdspan<double, std::dextents<int,2>> data){}"))
entries.extend(gen_with_entities("cpp", "Entity StdPrint", "printf(\"{e}: %d\\n\", val);", "std::print(\"{e}: {0}\\n\", val);"))
entries.extend(gen_with_entities("cpp", "Entity StdFormat", "std::string s = \"{e}: \" + std::to_string(val);", "std::string s = std::format(\"{e}: {}\", val);"))

print(f"C++: {len([e for e in entries if 'cpp' in e['tags']])} entries")

# Save intermediate
with open(OUTPUT.with_suffix('.cpp.json'), 'w') as f:
    json.dump([e for e in entries if 'cpp' in e['tags']], f, indent=2)

print(f"Total so far: {len(entries)}")
with open(OUTPUT, 'w') as f:
    json.dump(entries, f, indent=2)
print(f"Saved to: {OUTPUT}")