package p.studio.utilities.logs;

import org.slf4j.Logger;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

class LogAggregatorImpl implements LogAggregator {
    private final static String LINE_PATTERN = "%s %s \n";

    private final Consumer<String> logConsumer;
    private final Map<String, LogAggregator> cache = new ConcurrentHashMap<>();

    public LogAggregatorImpl(final Consumer<String> logConsumer) {
        this.logConsumer = logConsumer;
    }

    private void flush(final String kind, final String msg) {
        logConsumer.accept(LINE_PATTERN.formatted(kind, msg));
    }

    @Override
    public void trace(String msg) {
        flush("[TRACE]", msg);
    }

    @Override
    public void debug(String msg) {
        flush("[DEBUG]", msg);
    }

    @Override
    public void info(String msg) {
        flush("[INFO]", msg);
    }

    @Override
    public void warn(String msg) {
        flush("[WARN]", msg);
    }

    @Override
    public void error(String msg) {
        flush("[ERR]", msg);
    }

    @Override
    public void error(String msg, Throwable t) {
        error(msg);
    }

    @Override
    public LogAggregator using(final Logger logger) {
        return cache
                .computeIfAbsent(logger.getName(), __ -> buildNewLogAggregator(logger));
    }

    private LogAggregator buildNewLogAggregator(Logger logger) {
        final var aggregator = this;
        return new LogAggregator() {
            @Override
            public LogAggregator using(Logger logger) {
                return aggregator.using(logger);
            }

            @Override
            public void trace(String msg) {
                logger.trace(msg);
                aggregator.trace(msg);
            }

            @Override
            public void debug(String msg) {
                logger.debug(msg);
                aggregator.debug(msg);
            }

            @Override
            public void info(String msg) {
                logger.info(msg);
                aggregator.info(msg);
            }

            @Override
            public void warn(String msg) {
                logger.warn(msg);
                aggregator.warn(msg);
            }

            @Override
            public void error(String msg) {
                logger.error(msg);
                aggregator.error(msg);
            }

            @Override
            public void error(String msg, Throwable t) {
                logger.error(msg, t);
                aggregator.error(msg, t);
            }
        };
    }
}
