package net.viper.status.modules.chat;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

/**
 * Protokolliert alle Chat-Nachrichten in tagesweise rotierende Logdateien.
 *
 * Verzeichnis:  plugins/StatusAPI/chatlogs/chatlog_YYYY-MM-DD.log
 * Format:       [HH:mm:ss] [MSG-XXXXXX] [SERVER] [CHANNEL] Spieler: Nachricht
 *
 * Alte Logs werden beim Start und t\u00e4glich automatisch bereinigt.
 * Die Aufbewahrungsdauer ist in der chat.yml konfigurierbar (7 oder 14 Tage).
 */
public class ChatLogger {

    private final File logDir;
    private final Logger logger;
    private final int retentionDays;
    private final AtomicInteger counter = new AtomicInteger(0);

    // ThreadLocal: SimpleDateFormat ist NICHT thread-sicher – jeder Thread bekommt seine eigene Instanz.
    private static final ThreadLocal<SimpleDateFormat> DATE_FMT =
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
    private static final ThreadLocal<SimpleDateFormat> TIME_FMT =
        ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss"));

    public ChatLogger(File dataFolder, Logger logger, int retentionDays) {
        this.logDir        = new File(dataFolder, "chatlogs");
        this.logger        = logger;
        this.retentionDays = Math.max(1, retentionDays);
        this.logDir.mkdirs();
        cleanup();
    }

    // ===== Nachrichten-ID =====

    /**
     * Generiert eine eindeutige Nachrichten-ID (z.B. MSG-A3F2B1).
     * Kombiniert Zeitstempel + inkrementellen Z\u00e4hler f\u00fcr Eindeutigkeit.
     */
    public String generateMessageId() {
        int seq  = counter.incrementAndGet();
        long ts  = System.currentTimeMillis();
        int hash = (int)(ts ^ (ts >>> 32)) ^ (seq * 0x9E3779B9);
        return "MSG-" + String.format("%06X", hash & 0xFFFFFF);
    }

    // ===== Logging =====

    /**
     * Loggt eine Nachricht und gibt die generierte Nachrichten-ID zur\u00fcck.
     *
     * @param msgId    Vorher generierte ID (aus generateMessageId())
     * @param server   Servername des Absenders
     * @param channel  Kanal-ID
     * @param player   Spielername
     * @param message  Nachrichtentext (Rohtext, ohne Farbcodes)
     */
    public void log(String msgId, String server, String channel, String player, String message) {
        String date = DATE_FMT.get().format(new Date());
        String time = TIME_FMT.get().format(new Date());

        // Minecraft-Farbcodes aus dem Log entfernen
        String cleanMsg = stripColor(message);

        String line = "[" + time + "] [" + msgId + "] [" + server + "] [" + channel + "] "
                    + player + ": " + cleanMsg;

        File logFile = new File(logDir, "chatlog_" + date + ".log");
        try (BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(logFile, true), "UTF-8"))) {
            bw.write(line);
            bw.newLine();
        } catch (IOException e) {
            logger.warning("[ChatLogger] Fehler beim Schreiben: " + e.getMessage());
        }
    }

    // ===== Cleanup =====

    /**
     * L\u00f6scht Log-Dateien, die \u00e4lter als retentionDays Tage sind.
     * Wird beim Start und kann manuell aufgerufen werden.
     */
    public void cleanup() {
        if (!logDir.exists()) return;
        long cutoff = System.currentTimeMillis() - ((long) retentionDays * 24L * 60L * 60L * 1000L);
        File[] files = logDir.listFiles((dir, name) ->
                name.startsWith("chatlog_") && name.endsWith(".log"));
        if (files == null) return;
        for (File f : files) {
            if (f.lastModified() < cutoff) {
                if (f.delete()) {
                    logger.info("[ChatLogger] Altes Log gel\u00f6scht: " + f.getName());
                }
            }
        }
    }

    // ===== Hilfsmethoden =====

    /** Entfernt §-Farbcodes aus dem Text. */
    private static String stripColor(String input) {
        if (input == null) return "";
        return input.replaceAll("(?i)§[0-9A-FK-OR]", "")
                    .replaceAll("(?i)&[0-9A-FK-OR]", "");
    }

    public int getRetentionDays() { return retentionDays; }
    public File getLogDir()       { return logDir; }

    /**
     * Liest die letzten `maxLines` Zeilen aus dem heutigen Chatlog.
     * Wenn ein Spielername angegeben ist, werden nur seine Zeilen zur\u00fcckgegeben.
     *
     * @param playerFilter  Spielername (case-insensitiv) oder null f\u00fcr alle
     * @param maxLines      Maximale Anzahl zur\u00fcckgegebener Zeilen
     * @return Liste der Logzeilen (\u00e4lteste zuerst)
     */
    public List<String> readLastLines(String playerFilter, int maxLines) {
        String date = DATE_FMT.get().format(new Date());
        File logFile = new File(logDir, "chatlog_" + date + ".log");
        if (!logFile.exists()) return Collections.emptyList();

        List<String> allLines = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(logFile), "UTF-8"))) {
            String line;
            while ((line = br.readLine()) != null) {
                if (line.trim().isEmpty()) continue;
                // Spieler-Filter: Format ist [...] [...] [...] [...] Spieler: Nachricht
                if (playerFilter != null) {
                    // Spielername steht nach dem 4. [...]-Block
                    int lastBracket = line.indexOf("] ", line.lastIndexOf("["));
                    if (lastBracket >= 0) {
                        String rest = line.substring(lastBracket + 2);
                        String name = rest.contains(":") ? rest.substring(0, rest.indexOf(":")).trim() : "";
                        if (!name.equalsIgnoreCase(playerFilter)) continue;
                    }
                }
                allLines.add(line);
            }
        } catch (IOException e) {
            logger.warning("[ChatLogger] Fehler beim Lesen: " + e.getMessage());
        }

        // Letzte maxLines zur\u00fcckgeben
        if (allLines.size() <= maxLines) return allLines;
        return allLines.subList(allLines.size() - maxLines, allLines.size());
    }
}