package p21;

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 p21.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("path") String path, @ForAll("storageId") String storageId, @ForAll("repositoryId") String repositoryId) {
        if (caseCount.get() >= MAX_CASES) {
            return;
        }

        String result;
        try {
            result = GroundTruth.rewriteByStoreAndRepo(path, storageId, repositoryId);
        } catch (Exception e) {
            return;
        }

        Map<String, Object> inputs = new LinkedHashMap<>();
        inputs.put("path", path);
        inputs.put("storageId", storageId);
        inputs.put("repositoryId", repositoryId);
        generatedCases.add(new TestCase(inputs, result));
        caseCount.incrementAndGet();
    }

    @Example
    void example1() {
        generateTestCases("a/b/c/d", "s1", "r1");
    }

    @Example
    void example2() {
        generateTestCases("a/b/c/d/e", "s2", "r2");
    }

    @Example
    void example3() {
        generateTestCases("a/b", "s3", "r3");
    }

    @Example
    void example4() {
        generateTestCases("a/b/c", "s4", "r4");
    }

    @Example
    void example5() {
        generateTestCases("a/b/c/d/e/f", "s5", "r5");
    }

    @Provide
    Arbitrary<String> path() {
        return Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyz").ofMinLength(1).ofMaxLength(20)
                .flatMap(s1 -> Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyz").ofMinLength(1).ofMaxLength(20)
                        .flatMap(s2 -> Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyz").ofMinLength(1).ofMaxLength(20)
                                .flatMap(s3 -> Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyz").ofMinLength(1).ofMaxLength(20)
                                        .flatMap(s4 -> Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyz").ofMinLength(1).ofMaxLength(20)
                                                .map(s5 -> s1 + "/" + s2 + "/" + s3 + "/" + s4 + "/" + s5)))));
    }

    @Provide
    Arbitrary<String> storageId() {
        return Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyz0123456789").ofMinLength(1).ofMaxLength(10);
    }

    @Provide
    Arbitrary<String> repositoryId() {
        return Arbitraries.strings().withChars("abcdefghijklmnopqrstuvwxyz0123456789").ofMinLength(1).ofMaxLength(10);
    }

    @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);
    }
}