import json
from pathlib import Path

# ================== CONFIGURAZIONE ==================
INPUT_FILE = "telemetry_useful__grouped_ordered_filtered.json"
OUTPUT_FILE = "telemetry_useful__grouped_ordered_filtered_merged.json"
MERGE_THRESHOLD_SECONDS = 0.2
# ====================================================


def _get_event_time(ev):
    """
    Restituisce il timestamp principale dell'evento.
    Preferisce `timestamp_game` se disponibile, altrimenti `time`.
    """
    ts_game = ev.get("timestamp_game")
    if ts_game is not None:
        return ts_game
    return ev.get("time")


def _build_merged_event(cluster, start_time, end_time):
    """
    Costruisce un singolo evento "aggregato" a partire da un cluster di eventi
    consecutivi della stessa categoria di azione.

    - Copia il primo evento del cluster (preserva tutti i campi incluso test_date)
    - Aggiunge un campo `duration` (in secondi)
    - Mantiene il timestamp di start (timestamp_game/time del primo evento)
    """
    base_event = dict(cluster[0])  # copia superficiale del primo evento

    duration = None
    if start_time is not None and end_time is not None:
        # Garantiamo che la durata non sia negativa
        duration = max(0.0, float(end_time) - float(start_time))

    base_event["duration"] = duration
    return base_event


def merge_close_actions():
    """
    Carica `telemetry_useful__grouped_ordered_filtered.json` (eventi già
    raggruppati per utente e ordinati), e per ciascun utente:

    - scorre gli eventi in ordine
    - per ciascuna categoria di azione (`actionName`), unisce eventi consecutivi
      della stessa categoria se la distanza temporale tra loro è <= 0.3 secondi
      (MERGE_THRESHOLD_SECONDS)
    - ogni cluster di eventi viene sostituito da un singolo evento con:
        - timestamp di start (quello del primo evento del cluster)
        - campo `duration` = (ultimo_timestamp - primo_timestamp)
    - l'ordine degli eventi risultanti è preservato
    """
    script_dir = Path(__file__).parent
    processed_dir = script_dir / "processed"
    input_file = processed_dir / INPUT_FILE
    if not input_file.exists():
        raise FileNotFoundError(f"File non trovato: {input_file}")

    output_file = processed_dir / OUTPUT_FILE
    output_file.parent.mkdir(parents=True, exist_ok=True)

    # Carica il JSON raggruppato e filtrato
    with input_file.open("r", encoding="utf-8") as f:
        grouped = json.load(f)

    merged_grouped = {}

    for user_id, events in grouped.items():
        if not events:
            merged_grouped[user_id] = []
            continue

        merged_events = []

        current_cluster = []
        current_action = None
        cluster_start_time = None
        last_event_time = None

        for ev in events:
            action_name = ev.get("actionName")

            # Saltiamo le azioni di tipo "move_stop" per evitare ridondanza:
            # consideriamo solo le azioni di movimento (e le altre) nella sequenza.
            if action_name == "move_stop":
                continue

            ev_time = _get_event_time(ev)

            if not current_cluster:
                # Iniziamo un nuovo cluster
                current_cluster = [ev]
                current_action = action_name
                cluster_start_time = ev_time
                last_event_time = ev_time
                continue

            # Verifichiamo se possiamo unire questo evento al cluster corrente
            same_action = (action_name == current_action)
            can_merge = False

            if same_action and ev_time is not None and last_event_time is not None:
                if (ev_time - last_event_time) <= MERGE_THRESHOLD_SECONDS:
                    can_merge = True

            if can_merge:
                current_cluster.append(ev)
                last_event_time = ev_time
            else:
                # Chiudiamo il cluster corrente e lo trasformiamo in un singolo evento
                merged_event = _build_merged_event(
                    current_cluster,
                    cluster_start_time,
                    last_event_time,
                )
                merged_events.append(merged_event)

                # Avviamo un nuovo cluster con l'evento attuale
                current_cluster = [ev]
                current_action = action_name
                cluster_start_time = ev_time
                last_event_time = ev_time

        # Flush dell'ultimo cluster rimasto aperto
        if current_cluster:
            merged_event = _build_merged_event(
                current_cluster,
                cluster_start_time,
                last_event_time,
            )
            merged_events.append(merged_event)

        merged_grouped[user_id] = merged_events

    # Salva il nuovo file con eventi mergiati
    with output_file.open("w", encoding="utf-8") as f:
        json.dump(merged_grouped, f, indent=2)

    print(f"File con azioni mergiate salvato come: {output_file}")
    return output_file


if __name__ == "__main__":
    merge_close_actions()


