"""Session-Statistik: Loot-Rate, Bewegungsverlauf, Stuck- und Todes-Punkte.

Zaehlt Loot-Events (aus dem Chat-Middleware) und den Koordinatenverlauf
(aus dem Mainloop). Schreibt periodisch zwei Dateien, die das Dashboard
anzeigt: .pilotng-stats.json (Kennzahlen) und .pilotng-heatmap.json
(Punkte fuer die Karte). Exp-/Gold-Werte werden bewusst nicht geschaetzt.
"""
import json
import time
from pathlib import Path

STATS_FILE = Path('.pilotng-stats.json')
HEATMAP_FILE = Path('.pilotng-heatmap.json')
MAX_POINTS = 1500
STUCK_AFTER_SECONDS = 90
JUMP_MIN_DISTANCE = 20


class SessionStats:
    def __init__(self, stats_file=STATS_FILE, heatmap_file=HEATMAP_FILE):
        self.statsFile = stats_file
        self.heatmapFile = heatmap_file
        self.startedAt = time.time()
        self.lootEvents = 0
        self.points = []
        self.stucks = []
        self.jumps = []
        self._lastCoord = None
        self._lastCoordAt = None
        self._lastSaveAt = 0.0

    def lootEvent(self):
        self.lootEvents += 1

    def tick(self, coordinate, now=None):
        now = time.time() if now is None else now
        if coordinate is None:
            return
        x, y, z = coordinate
        current = (x, y, z)
        if self._lastCoord is not None and current != self._lastCoord:
            distance = (abs(x - self._lastCoord[0]) +
                        abs(y - self._lastCoord[1]) +
                        abs(z - self._lastCoord[2]) * 15)
            if distance >= JUMP_MIN_DISTANCE:
                self.jumps.append({
                    'from': list(self._lastCoord),
                    'to': list(current),
                    'at': now,
                })
        if current == self._lastCoord:
            if (self._lastCoordAt is not None and
                    now - self._lastCoordAt >= STUCK_AFTER_SECONDS):
                self.stucks.append({
                    'coordinate': list(current),
                    'seconds': int(now - self._lastCoordAt),
                    'at': now,
                })
                self._lastCoordAt = now
        else:
            self._lastCoord = current
            self._lastCoordAt = now
            self.points.append([x, y, z, now])
            if len(self.points) > MAX_POINTS:
                self.points = self.points[-1000:]
        if now - self._lastSaveAt >= 30:
            self._lastSaveAt = now
            self.save(now)

    def summary(self, now=None):
        now = time.time() if now is None else now
        hours = max((now - self.startedAt) / 3600, 1 / 3600)
        return {
            'minutes': int((now - self.startedAt) / 60),
            'lootEvents': self.lootEvents,
            'lootPerHour': round(self.lootEvents / hours, 1),
            'pointsVisited': len(self.points),
            'stucks': len(self.stucks),
            'jumps': len(self.jumps),
        }

    def save(self, now=None):
        now = time.time() if now is None else now
        try:
            self.statsFile.write_text(
                json.dumps(self.summary(now)), encoding='utf-8')
            self.heatmapFile.write_text(json.dumps({
                'points': self.points[-600:],
                'stucks': self.stucks[-20:],
                'jumps': self.jumps[-10:],
            }), encoding='utf-8')
        except OSError:
            pass


stats = SessionStats()
