package p104;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import net.jqwik.api.*;
import net.jqwik.api.lifecycle.AfterContainer;
import p104.GroundTruth;

public class TestCaseGenerator {

    static class TestCase {
        Map<String, Object> Inputs;
        Object Expected;
        TestCase(Map<String, Object> inputs, Object expected) {
            this.Inputs = inputs;
            this.Expected = expected;
        }
    }

    static List<TestCase> generatedCases = new ArrayList<>();
    static AtomicInteger caseCount = new AtomicInteger(0);
    static final int MAX_CASES = 500;

    @Property(tries = 10000)
    void generateTestCases(
            @ForAll("generateString") String string,
            @ForAll("generateChar") char delimiter,
            @ForAll("generateCursor") int cursor,
            @ForAll("generateBuilder") StringBuilder builder) {
        if (caseCount.get() >= MAX_CASES) {
            return;
        }

        int result;
        try {
            result = GroundTruth.consumeUnquoted(string, delimiter, cursor, builder);
        } catch (Exception e) {
            return;
        }

        Map<String, Object> inputs = new LinkedHashMap<>();
        inputs.put("string", string);
        inputs.put("delimiter", delimiter);
        inputs.put("cursor", cursor);
        inputs.put("builder", builder.toString());
        generatedCases.add(new TestCase(inputs, result));
        caseCount.incrementAndGet();
    }

    @Example
    void example1() {
        generateTestCases("abc,def", ',', 0, new StringBuilder());
    }

    @Example
    void example2() {
        generateTestCases("xyz|123", '|', 3, new StringBuilder());
    }

    @Example
    void example3() {
        generateTestCases("hello world", ' ', 0, new StringBuilder());
    }

    @Provide
    Arbitrary<String> generateString() {
        return Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.|").ofMinLength(0).ofMaxLength(20);
    }

    @Provide
    Arbitrary<Character> generateChar() {
        return Arbitraries.chars().with('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ',', '.', '|');
    }

    @Provide
    Arbitrary<Integer> generateCursor() {
        return Arbitraries.integers().between(0, 20);
    }

    @Provide
    Arbitrary<StringBuilder> generateBuilder() {
        return Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.|").ofMinLength(0).ofMaxLength(20).map(StringBuilder::new);
    }

    @AfterContainer
    static void saveTestCases() throws IOException {
        if (generatedCases.isEmpty()) {
            return;
        }
        String dirPath = "src/test/java/test_cases";
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String filePath = dirPath + "/test_cases.json";
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        try (Writer writer = new FileWriter(filePath)) {
            gson.toJson(generatedCases, writer);
        }
        System.out.println("✅ Saved " + generatedCases.size() + " test cases to " + filePath);
    }
}