package org.example;

import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

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

class LoggingHygieneRegressionTest {

    @Test
    void productionJavaDoesNotUseConsoleLogging() throws IOException {
        Path sourceRoot = moduleRoot().resolve("src/main/java");
        List<String> violations;
        try (Stream<Path> files = Files.walk(sourceRoot)) {
            violations = files
                    .filter(path -> path.toString().endsWith(".java"))
                    .flatMap(path -> activeLines(path).stream())
                    .filter(line -> line.contains("System.out")
                            || line.contains("System.err")
                            || line.contains("printStackTrace"))
                    .toList();
        }

        assertEquals(List.of(), violations);
    }

    @Test
    void productionJavaDoesNotUseStaticConsoleAliases() throws IOException {
        Path sourceRoot = moduleRoot().resolve("src/main/java");
        List<String> violations;
        try (Stream<Path> files = Files.walk(sourceRoot)) {
            violations = files
                    .filter(path -> path.toString().endsWith(".java"))
                    .flatMap(path -> activeLines(path).stream())
                    .filter(line -> line.contains("import static java.lang.System.out")
                            || line.contains("import static java.lang.System.err")
                            || line.matches(".*\\b(out|err)\\.(print|println|printf)\\s*\\(.*"))
                    .toList();
        }

        assertEquals(List.of(), violations);
    }

    @Test
    void mybatisUsesSlf4jInsteadOfStdoutLogging() throws IOException {
        String applicationProperties = Files.readString(moduleRoot().resolve("src/main/resources/application.properties"));

        assertFalse(applicationProperties.contains("org.apache.ibatis.logging.stdout.StdOutImpl"));
        assertTrue(applicationProperties.contains("mybatis.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl"));
    }

    private static Path moduleRoot() {
        Path current = Path.of("").toAbsolutePath();
        if (Files.exists(current.resolve("src/main/java"))) {
            return current;
        }
        Path childModule = current.resolve("weberp");
        if (Files.exists(childModule.resolve("src/main/java"))) {
            return childModule;
        }
        throw new IllegalStateException("Cannot locate weberp module root from " + current);
    }

    private static List<String> activeLines(Path path) {
        try {
            List<String> lines = Files.readAllLines(path);
            return IntStream.range(0, lines.size())
                    .filter(index -> {
                        String stripped = lines.get(index).stripLeading();
                        return !stripped.startsWith("//") && !stripped.startsWith("*");
                    })
                    .mapToObj(index -> path + ":" + (index + 1) + ":" + lines.get(index))
                    .toList();
        } catch (IOException ex) {
            throw new IllegalStateException("Cannot read " + path, ex);
        }
    }
}
