package org.xbib.logging.ext.test.formatters;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.xbib.logging.ext.formatters.PatternFormatter;
import org.xbib.logging.ext.formatters.TextBannerFormatter;

/**
 * Tests of the banner formatting capability.
 */
public class BannerFormatterTests {

    public static final String FALLBACK_OK = "fallback OK!";
    public static final String TEST_BANNER_FILE = "Test banner file!\n";

    public BannerFormatterTests() {
    }

    @Test
    public void testBanner() throws Exception {
        final PatternFormatter emptyFormatter = new PatternFormatter("");
        final Supplier<String> fallbackSupplier = TextBannerFormatter.createStringSupplier(FALLBACK_OK);
        Assertions.assertEquals("", emptyFormatter.getHead(null));
        Assertions.assertEquals(FALLBACK_OK, fallbackSupplier.get());
        TextBannerFormatter tbf = new TextBannerFormatter(fallbackSupplier, emptyFormatter);
        Assertions.assertEquals(FALLBACK_OK, tbf.getHead(null));
        tbf = new TextBannerFormatter(createResourceSupplier("non-existent-banner.txt", fallbackSupplier), emptyFormatter);
        Assertions.assertEquals(FALLBACK_OK, tbf.getHead(null));
        tbf = new TextBannerFormatter(createResourceSupplier("test-banner.txt", fallbackSupplier), emptyFormatter);
        final InputStream is = getClass().getResourceAsStream("/org/xbib/logging/ext/test/formatters/test-banner.txt");
        Assertions.assertNotNull(is);
        try (is) {
            final String s = new String(is.readAllBytes(), StandardCharsets.UTF_8);
            Assertions.assertEquals(s, tbf.getHead(null));
        }
        final Path tempFile = Files.createTempFile(Path.of(System.getProperty("user.dir"),"build"), "banner-format", null);
        try {
            Files.writeString(tempFile, TEST_BANNER_FILE);
            tbf = new TextBannerFormatter(TextBannerFormatter.createFileSupplier(tempFile, fallbackSupplier), emptyFormatter);
            Assertions.assertEquals(TEST_BANNER_FILE, tbf.getHead(null));
            // and, the URL version...
            tbf = new TextBannerFormatter(TextBannerFormatter.createUrlSupplier(tempFile.toUri().toURL(), fallbackSupplier),
                    emptyFormatter);
            Assertions.assertEquals(TEST_BANNER_FILE, tbf.getHead(null));
        } finally {
            try {
                Files.delete(tempFile);
            } catch (Throwable ignored) {
            }
        }
        // non-existent file
        tbf = new TextBannerFormatter(TextBannerFormatter.createFileSupplier(Path.of("does not exist"), fallbackSupplier),
                emptyFormatter);
        Assertions.assertEquals(FALLBACK_OK, tbf.getHead(null));
    }

    /**
     * Create a supplier which loads the banner from a resource in the given class loader,
     * falling back to the given fallback supplier on error.
     *
     * @param resource    the resource name (must not be {@code null})
     * @param fallback    the fallback supplier (must not be {@code null})
     * @return the supplier (not {@code null})
     */
    private Supplier<String> createResourceSupplier(String resource, Supplier<String> fallback) {
        Objects.requireNonNull(resource, "resource");
        Objects.requireNonNull(fallback, "fallback");
        return () -> {
            try {
                final InputStream is = getClass().getResourceAsStream(resource);
                return is == null ? fallback.get() : loadStringFromStream(is);
            } catch (IOException ignored) {
                return fallback.get();
            }
        };
    }

    private static String loadStringFromStream(final InputStream is) throws IOException {
        try (is) {
            return new String(is.readAllBytes(), StandardCharsets.UTF_8);
        }
    }
}
