package com.dragontcp.client;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public final class AppLog {
    public interface Listener { void onLine(String line); }

    private static final int MAX_LINES = 600;
    private static final ArrayDeque<String> lines = new ArrayDeque<>();
    private static final CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<>();
    private static String lastLine;
    private static int repeatCount;

    private AppLog() {}

    public static void append(String line) {
        if (line == null) return;
        line = line.trim();
        if (line.isEmpty()) return;

        // The core emits one adaptation line per proxied flow, so a busy page
        // load produces dozens of identical entries. Collapse consecutive
        // repeats into a single counted line instead of burying the log.
        String emit;
        synchronized (lines) {
            if (line.equals(lastLine)) {
                repeatCount++;
                return;
            }
            if (repeatCount > 0) {
                String summary = "  (previous line repeated " + repeatCount + " more times)";
                repeatCount = 0;
                push(summary);
                notifyListeners(summary);
            }
            lastLine = line;
            push(line);
            emit = line;
        }
        notifyListeners(emit);
    }

    /** Caller must hold the {@code lines} lock. */
    private static void push(String line) {
        while (lines.size() >= MAX_LINES) lines.removeFirst();
        lines.addLast(line);
    }

    private static void notifyListeners(String line) {
        for (Listener listener : listeners) {
            try { listener.onLine(line); } catch (Throwable ignored) {}
        }
    }

    public static String history() {
        StringBuilder out = new StringBuilder();
        synchronized (lines) {
            for (String line : lines) out.append(line).append('\n');
        }
        return out.toString();
    }

    public static void clear() {
        synchronized (lines) {
            lines.clear();
            lastLine = null;
            repeatCount = 0;
        }
    }

    public static void addListener(Listener listener) { listeners.addIfAbsent(listener); }
    public static void removeListener(Listener listener) { listeners.remove(listener); }
}
