package ai.nektron.grownet.tests;

import ai.nektron.grownet.debug.GrowNetTraceMain;
import ai.nektron.grownet.debug.TraceRunSummary;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Writer;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class TraceRunnerTests {

    @Test
    public void singleNeuronTraceContainsSlotSelect() throws Exception {
        String output = GrowNetTraceMain.runForTest(
                "--lang", "java",
                "--trace",
                "--scenario", "single_neuron",
                "--value", "0.42"
        );
        assertTrue(output.contains("[slot.select]"));
    }

    @Test
    public void growthTraceContainsNeuronCreate() throws Exception {
        String output = GrowNetTraceMain.runForTest(
                "--lang", "java",
                "--trace",
                "--scenario", "growth",
                "--value", "0.42"
        );
        assertTrue(output.contains("[growth.neuron.create]"));
    }

    @Test
    public void jsonlTraceLooksLikeJsonObjects() throws Exception {
        String output = GrowNetTraceMain.runForTest(
                "--lang", "java",
                "--trace",
                "--trace-format", "jsonl",
                "--scenario", "single_neuron",
                "--value", "0.42"
        );
        String[] lines = output.split("\\R");
        assertTrue(lines.length > 0);
        assertTrue(lines[0].startsWith("{"));
        assertTrue(lines[0].endsWith("}"));
        assertTrue(lines[0].contains("\"event\":\"tick.start\""));
    }

    @Test
    public void filteringSuppressesTickEvents() throws Exception {
        String output = GrowNetTraceMain.runForTest(
                "--lang", "java",
                "--trace",
                "--trace-format", "jsonl",
                "--trace-events", "slot,growth",
                "--scenario", "growth",
                "--value", "0.42"
        );
        assertFalse(output.contains("\"event\":\"tick.start\""));
        assertTrue(output.contains("\"event\":\"growth.neuron.create\""));
    }

    @Test
    public void exactEventNameFilteringKeepsOnlyThresholdUpdates() throws Exception {
        String output = GrowNetTraceMain.runForTest(
                "--lang", "java",
                "--trace",
                "--trace-format", "jsonl",
                "--trace-events", "threshold.update",
                "--scenario", "single_neuron",
                "--value", "0.42"
        );
        assertTrue(output.contains("\"event\":\"threshold.update\""));
        assertFalse(output.contains("\"event\":\"slot.select\""));
        assertFalse(output.contains("\"event\":\"tick.start\""));
    }

    @Test
    public void failingTraceWriterDoesNotAbortTickPaths() throws Exception {
        TraceRunSummary baselineSummary = GrowNetTraceMain.runSummaryForTest(
                "--lang", "java",
                "--trace",
                "--trace-format", "jsonl",
                "--scenario", "growth",
                "--value", "0.42"
        );
        TraceRunSummary failingWriterSummary = GrowNetTraceMain.runSummaryForTestWithWriter(
                new AlwaysFailingWriter(),
                "--lang", "java",
                "--trace",
                "--trace-format", "jsonl",
                "--scenario", "growth",
                "--value", "0.42"
        );
        assertEquals(baselineSummary, failingWriterSummary);
    }

    private static final class AlwaysFailingWriter extends Writer {
        @Override
        public void write(char[] buffer, int offset, int length) throws IOException {
            throw new IOException("synthetic trace writer failure");
        }

        @Override
        public void flush() throws IOException {
            throw new IOException("synthetic trace writer failure");
        }

        @Override
        public void close() {
        }
    }
}
