Autodarts - Better X01-Stats

Better stats-table

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Autodarts - Better X01-Stats
// @namespace    http://tampermonkey.net/
// @version      0.79
// @description  Better stats-table
// @author       benebelter
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @require      https://update.greasyfork.org/scripts/570871/AD%20-%20Bearer-update%20v3.js
// @match        https://play.autodarts.io/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=autodarts.io
// @license      MIT
// @run-at       document-end
// ==/UserScript==


(function () {
    'use strict';
    const NAME_COL_WIDTH = "200px";
    const COL_WIDTH_1 = "50px";
    let currentGameId = null;


    let LANG = "en";

function detectLanguage() {
    let uiLang =
        localStorage.getItem("i18nextLng") ||
        localStorage.getItem("language") ||
        "";

    let browserLang = navigator.language || "";

    let lang = (uiLang || browserLang).toLowerCase();

    if (lang.startsWith("de")) {
        LANG = "de";
    } else if (lang.startsWith("nl")) {
        LANG = "nl";
    } else {
        LANG = "en";
    }
}

const TEXT = {
    en: {
        matchStats: "📊 Match Stats",
        avg: "Avg",
        first9: "First 9",
        to170: "— 170",
        trebles: "Trebless",
        triples: "T17 — T20",
        corrections: "Corrections",
        checkout: "Checkout",
        highest: "Highest",
        finishes: "90+ Finishes",
        dartsRest: "<span style='color: #00e676;'>Darts</span> / <span style='color: grey'>Rest</span>",
        noticeTitle: "⚠️ Notice:",
        noticeText: "A winning dart was corrected by the system. Hover over the value for details.",
        corrected: "has been corrected for the win"
    },
    de: {
        matchStats: "📊 Match Statistiken",
        avg: "Avg",
        first9: "First 9",
        to170: "— 170",
        trebles: "Ohne Triple",
        triples: "T17 — T20",
        corrections: "Korrekturen",
        checkout: "Checkout",
        highest: "Höchstes",
        finishes: "90+ Finishes",
        dartsRest: "<span style='color: #00e676;'>Darts</span> / <span style='color: grey'>Rest</span>",

        noticeTitle: "⚠️ Hinweis:",
        noticeText: "Ein Leg-Finish wurde vom System korrigiert. Fahre mit der Maus über den Wert für Details.",
        corrected: "wurde für den Gewinn korrigiert"
    },
    nl: {
        matchStats: "📊 Wedstrijd Statistieken",
        avg: "Gem",
        first9: "Eerste 9",
        to170: "— 170",
        trebles: "Zonder Triple",
        triples: "T17 — T20",
        corrections: "Correcties",
        checkout: "Checkout",
        highest: "Hoogste",
        finishes: "90+ Finishes",
        dartsRest: "<span style='color: #00e676;'>Darts</span> / <span style='color: grey'>Rest</span>",
        noticeTitle: "⚠️ Opmerking:",
        noticeText: "Een winnende dart werd door het systeem gecorrigeerd. Beweeg met de muis over de waarde voor details.",
        corrected: "is gecorrigeerd voor de winst"
    }
};

function t(key) {
    try {
        return TEXT?.[LANG]?.[key] ?? key;
    } catch {
        return key;
    }
}

    async function getMatchStats(gameid) {
        const res = await fetch(
            'https://api.autodarts.io/as/v0/matches/' + gameid + '/stats',
            {
                credentials: 'include',
                headers: { "Authorization": localStorage.getItem("bearer") },
            }
        );
        return await res.json();
    }

    function buildStats(match) {
        const customScoreMap = countCustomScores(match);
        const highFinishListMap = getHighFinishList(match);
        const nonDetectedMap = countNonDetectedThrows(match);
        const tripleMap = countHighTriples(match);
        const noTripleMap = countNoTripleOver100(match);

        const result = {};
        const playerMap = {};

        // 👉 Player-ID → Name
        match.players.forEach(p => {
            playerMap[p.id] = p.name;
        });

        match.matchStats.forEach(s => {
            const name = playerMap[s.playerId];
            if (!name) return;

            const upper = name.toUpperCase();

            const attempts = s.checkouts ?? 0;
            const hits = s.checkoutsHit ?? 0;

            result[name] = {
                counts: {
                    // ✅ FIX: Uppercase Key verwenden
                    highFinishList: highFinishListMap[upper] ?? [],

                    nonDetected: nonDetectedMap[upper] ?? 0,
                    noTriple100: noTripleMap[name] ?? 0,
                    triplesHigh: tripleMap[upper] ?? 0,

                    "60+": s.plus60 ?? 0,
                    "90+": customScoreMap[upper]?.["90+"] ?? 0,
                    "130+": customScoreMap[upper]?.["130+"] ?? 0,
                    "171+": customScoreMap[upper]?.["171+"] ?? 0,
                    "170+": s.plus170 ?? 0,
                    "180": s.total180 ?? 0
                },

                averages: {
                    total: s.average ?? 0,
                    first9: s.first9Average ?? 0,
                    to170: s.averageUntil170 ?? 0
                },

                checkout: {
                    attempts,
                    hits,
                    percentage: attempts > 0 ? (hits / attempts) * 100 : 0,
                    high: s.checkoutPoints ?? 0
                }
            };
        });

        return result;
    }

    function buildLegStats(match) {
        const isOnlineGame = !!match.host;
        const playerMap = {};
        match.players.forEach(p => {
            playerMap[p.id] = p.name;
        });

        const START_SCORE =
              match?.settings?.baseScore ??
              match?.games?.[0]?.settings?.baseScore ??
              501;


        const legs = [];

        match.games?.forEach((game, index) => {
            const leg = {
                leg: index + 1,
                set: game.set ?? 0,
                players: {}
            };

            const scorePerPlayer = {};
            const dartsPerPlayer = {};
            const correctedMap = {};
            const correctedDetailMap = {};

            match.players.forEach(p => {
                scorePerPlayer[p.id] = START_SCORE;
                dartsPerPlayer[p.id] = 0;
                correctedMap[p.id] = false;
                correctedDetailMap[p.id] = ""; // 👈 NEU
            });

            game.turns?.forEach(turn => {
                const pid = turn.playerId;

                let scored =
                    turn.points ??
                    turn.score ??
                    turn.roundScore ??
                    0;

                let darts =
                    turn.dartsThrown ??
                    turn.darts ??
                    3;

                if (scorePerPlayer[pid] > 0) {

                    // 🎯 Checkout Turn
                    if (scorePerPlayer[pid] - scored <= 0) {

                        let remaining = scorePerPlayer[pid];
                        let usedDarts = 0;

                        const throws = turn.throws ?? [];

                        let corrected = false;
                        let correctedDetail = "";

                        const GOOD_ENTRIES = [
                            "detected",
                            "corrected_bouncer",
                            "referee_ai_corrected",
                            "corrected_after_referee_ai",
                            "referee_ai_confirmed"
                        ];

                        if (throws.length > 0) {
                            for (let th of throws) {

                                const val =
                                      th?.points ??
                                      th?.value ??
                                      (th?.segment?.multiplier ?? 0) * (th?.segment?.number ?? 0);

                                remaining -= val;
                                usedDarts++;

                                if (remaining <= 0) {



                                    const VALID_ENTRIES = [
                                        "detected",
                                        "corrected_bouncer",
                                        "referee_ai_corrected",
                                        "corrected_after_referee_ai",
                                        "referee_ai_confirmed"
                                    ];

                                    if (!VALID_ENTRIES.includes(th.entry)) {
                                        corrected = true;
                                        const seg = th?.segment?.name ?? "";
                                        correctedDetail = `⚠️ ${seg} ${t("corrected")}`;
                                    }



                                    break;
                                }
                            }

                            darts = usedDarts;
                        }

                        scorePerPlayer[pid] = 0;
                        dartsPerPlayer[pid] += darts;
                        correctedMap[pid] = corrected;
                        correctedDetailMap[pid] = correctedDetail;

                    } else {
                        scorePerPlayer[pid] -= scored;
                        dartsPerPlayer[pid] += darts;
                    }
                }
            });

            // 👉 FINAL setzen
            match.players.forEach(p => {
                const id = p.id;
                const name = playerMap[id];
                const remaining = scorePerPlayer[id];

                const winnerId = game.winnerPlayerId ?? game.winner;

                if (id === winnerId) {
                    leg.players[name] = {
                        type: "darts",
                        value: dartsPerPlayer[id],
                        correctedFinish: correctedMap[id],
                        correctedDetail: correctedDetailMap[id]
                    };
                } else {
                    leg.players[name] = {
                        type: "remaining",
                        value: remaining
                    };
                }
            });

            legs.push(leg);
        });

        return legs;
    }








    function appendDate(match) {

        // ❌ Schon vorhanden → nichts tun
        if (document.querySelector("#ad-dateplayed")) return;

        const target = document.querySelector(".css-a6m3v9");
        if (!target) return;

        // 👉 mögliche Felder aus der API
        const rawDate =
              match.finishedAt ??
              match.endedAt ??
              match.startedAt ??
              null;

        const span = document.createElement("span");
        span.id = "ad-dateplayed";
        span.className = "css-1xbroe7";

        // ❌ kein Datum vorhanden
        if (!rawDate) {
            span.textContent = "läuft aktuell...";
            target.appendChild(span);
            return;
        }

        const date = new Date(rawDate);

        // ❌ ungültiges Datum
        if (isNaN(date.getTime())) {
            span.textContent = "läuft aktuell...";
            target.appendChild(span);
            return;
        }

        // ✅ korrekt formatieren
        const LOCALE_MAP = {
            en: "en-US",
            de: "de-DE",
            nl: "nl-NL"
        };
        const locale = LOCALE_MAP[LANG] || "en-US";

        const formatted = date.toLocaleString(locale, {
            day: "numeric",
            month: "short",
            year: "numeric",
            hour: "2-digit",
            minute: "2-digit"
        });

        // 👉 wenn Match noch läuft
        if (!match.finishedAt) {
            span.textContent = "läuft aktuell...";
        } else {
            span.textContent = LANG === "de" ? formatted + " Uhr" : formatted;
        }

        target.appendChild(span);
    }






    function render(stats, match) {

        detectLanguage();

        if (!match?.variant || !match.variant.toLowerCase().includes("x01")) {
            return;
        }
        appendDate(match);


        const players = Object.values(stats);

        const bestAvg = Math.max(...players.map(p => p.averages.total || 0));
        const bestFirst9 = Math.max(...players.map(p => p.averages.first9 || 0));
        const bestTo170 = Math.max(...players.map(p => p.averages.to170 || 0));
        const bestCheckout = Math.max(...players.map(p => p.checkout.percentage || 0));
        const bestCheckoutRounded = Math.round(bestCheckout * 100) / 100;

        document.querySelector('#ad-stats')?.remove();

        const container = document.createElement('div');
        container.id = "ad-stats";
        container.style.width = "96%";
        container.style.maxWidth = "96%";
        container.style.margin = "5px 2% 20px";
        container.style.padding = "12px";
        container.style.background = "#111";
        container.style.color = "#fff";
        container.style.border = "1px solid #333";
        container.style.borderRadius = "8px";
        container.style.fontFamily = "Arial";
        container.style.fontSize = "16px";
        container.style.boxShadow = "0 6px 20px rgba(0,0,0,0.5)";
        container.style.fontVariantNumeric = "tabular-nums";

        let html = `<div style="font-weight:bold; margin-bottom:10px; font-size: 3.0em; text-align: center;">${t("matchStats")}</div>`;

        // 🔥 Highscores
        html += `
<table style="
    width:auto;
    border-collapse: collapse;
    margin-bottom:12px;
    table-layout:fixed;
">
    <colgroup>
        <col style="width:${NAME_COL_WIDTH};">
        <col style="width:70px;">
        <col style="width:70px;">
        <col style="width:70px;">
        <col style="width:70px;">
        <col style="width:70px;">
    </colgroup>
    <tr style="border-bottom:1px solid #444;">
        <th style="text-align:left"></th>
        <th style="text-align:center">60+</th>
        <th style="text-align:center">90+</th>
        <th style="text-align:center">130+</th>
        <th style="text-align:center">171+</th>
        <th style="text-align:center">180</th>
    </tr>
`;



        Object.entries(stats).forEach(([name, s]) => {
            html += `
    <tr>
        <td style="text-align:left; padding-right:10px;  text-transform:uppercase;">
            ${name}
        </td>

        <td style="text-align:center;">
            ${s.counts["60+"] ?? 0}
        </td>

        <td style="text-align:center; color:#ffd700;">
            ${s.counts["90+"] ?? 0}
        </td>

        <td style="text-align:center; color:#ff8c00;">
            ${s.counts["130+"] ?? 0}
        </td>
        <td style="text-align:center; color:#ff8c00;">
        ${s.counts["171+"] ?? 0}
        </td>
        <td style="text-align:center; color:#ff4d4d;">
            ${s.counts["180"] ?? 0}
        </td>
    </tr>
    `;
        });
        html += `</table>`;


        // 📈 Averages

        const bestClean = Math.min(...players.map(p => p.counts.noTriple100 || 0));
        const bestTriplesHigh = Math.max(...players.map(p => p.counts.triplesHigh || 0));

        const bestNonDetected = Math.min(...players.map(p => p.counts.nonDetected ?? Infinity));

        html += `
<table style="
    width:auto;
    border-collapse: collapse;
    margin-bottom:12px;
    table-layout:fixed;
">
    <colgroup>
        <col style="width:${NAME_COL_WIDTH};">
        <col style="width:80px;">
        <col style="width:80px;">
        <col style="width:80px;">
        <col style="width:110px;">
        <col style="width:110px;">
        <col style="width:110px;">
    </colgroup>

    <tr style="border-bottom:1px solid #444;">
    <th style="text-align:center"></th>
<th style="text-align:center">${t("avg")}</th>
<th style="text-align:center">${t("first9")}</th>
<th style="text-align:center">${t("to170")}</th>
<th style="text-align:center">${t("trebles")}</th>
<th style="text-align:center">${t("triples")}</th>
<th style="text-align:center">${t("corrections")}</th>
    </tr>
`;

        Object.entries(stats).forEach(([name, s]) => {
            html += `
    <tr>
        <td style="
            text-align:left;
            padding-right:10px;
            text-transform:uppercase;
        ">
            ${name}
        </td>

        <td style="
            text-align:center;
            color: ${s.averages.total === bestAvg ? '#00e676' : 'inherit'};
            font-weight: ${s.averages.total === bestAvg ? 'bold' : 'normal'};
        ">
            ${(s.averages.total ?? 0).toFixed(2)}
        </td>

        <td style="
            text-align:center;
            color: ${s.averages.first9 === bestFirst9 ? '#00e676' : 'inherit'};
            font-weight: ${s.averages.first9 === bestFirst9 ? 'bold' : 'normal'};
        ">

            ${(s.averages.first9 ?? 0).toFixed(2)}
        </td>

        <td style="
            text-align:center;
            color: ${s.averages.to170 === bestTo170 ? '#00e676' : 'inherit'};
            font-weight: ${s.averages.to170 === bestTo170 ? 'bold' : 'normal'};
        ">

             ${(s.averages.to170 ?? 0).toFixed(2)}
        </td>

        <!-- 🟢 Clean (weniger ist besser!) -->
        <td style="
            text-align:center;
            color: ${s.counts.noTriple100 === bestClean ? '#00e676' : 'inherit'};
            font-weight: ${s.counts.noTriple100 === bestClean ? 'bold' : 'normal'};
        ">
            ${s.counts.noTriple100}
        </td>

        <!-- 🎯 Triple -->
<td style="
    text-align:center;
    color: ${s.counts.triplesHigh === bestTriplesHigh ? '#00e676' : 'inherit'};
    font-weight: ${s.counts.triplesHigh === bestTriplesHigh ? 'bold' : 'normal'};
">
    ${s.counts.triplesHigh ?? 0}
</td>

<td style="
    text-align:center;
    color: ${s.counts.nonDetected === bestNonDetected ? '#00e676' : '#ff5252'};
    font-weight: ${s.counts.nonDetected === bestNonDetected ? 'bold' : 'normal'};
">
    ${s.counts.nonDetected}
</td>
    </tr>
    `;
        });

        html += `</table>`;



        // 🎯 Checkout
        const bestHigh = Math.max(...players.map(p => p.checkout.high || 0));

        html += `
<table style="
    width:auto;
    border-collapse: collapse;
    margin-bottom:12px;
    table-layout:fixed;
">
 <colgroup>
    <col style="width:${NAME_COL_WIDTH};">
    <col style="width:140px;">
    <col style="width:140px;">
    <col style="width:300px;">  <!-- 👈 NEU -->
</colgroup>
<tr style="border-bottom:1px solid #444;">
<th style="text-align:center"> </th>
<th style="text-align:center">${t("checkout")}</th>
<th style="text-align:center">${t("highest")}</th>
<th style="text-align:left">${t("finishes")}</th>

</tr>
`;

        Object.entries(stats).forEach(([name, s]) => {
            html += `
<tr>
    <td style="
        text-align:left;
        padding-right:10px;
        text-transform:uppercase;
    ">
        ${name}
    </td>

    <td style="text-align:center;">
        <span style="
            font-weight:bold;

            color: ${
    (Math.round((s.checkout.percentage ?? 0) * 100) / 100) === bestCheckoutRounded
        ? '#00e676'
        : 'inherit'
};
        ">
            ${s.checkout.percentage.toFixed(2)} %
        </span>
        <span style="opacity:0.6; margin-left:4px;">
            (${s.checkout.hits}/${s.checkout.attempts})
        </span>
    </td>

    <td style="
        text-align:center;
        font-weight:bold;
        color: ${s.checkout.high === bestHigh ? '#00e676' : 'inherit'};
    ">
        ${s.checkout.high > 0 ? s.checkout.high : ""}
    </td>

    <!-- 👇 WICHTIG: eigenes TD -->
    <td style="
        text-align:left;
        padding-left:10px;
        font-size:0.9em;
        opacity:0.85;
    ">
        ${s.counts.highFinishList.length > 0
                ? s.counts.highFinishList.join(", ")
            : "--"}
    </td>
</tr>
    `;
        });

        html += `</table>`;
        // 🟢 Leg Übersicht
        const legs = buildLegStats(match);

        const setGroups = [];
        let currentSet = null;

        legs.forEach((l, i) => {
            if (l.set !== currentSet) {
                setGroups.push({
                    set: l.set,
                    start: i,
                    count: 1
                });
                currentSet = l.set;
            } else {
                setGroups[setGroups.length - 1].count++;
            }
        });


        let hasCorrections = false;

        legs.forEach(l => {
            Object.values(l.players).forEach(p => {
                if (p.correctedFinish) {
                    hasCorrections = true;
                }
            });
        });

        if (legs.length > 0) {

            html += `
    <table style="
        width:auto;
        border-collapse: collapse;
        margin-top:8px;
        table-layout:fixed;
    ">
        <colgroup>
            <col style="width:${NAME_COL_WIDTH};">
            ${legs.map(() => `<col style="width:70px;">`).join("")}
        </colgroup>

        <tr style="border-bottom:1px solid #444;">

            <th style="text-align:left">${t("dartsRest")}</th>
            ${legs.map((l, i) => {
                const prevSet = legs[i - 1]?.set;
                const isNewSet = i > 0 && l.set !== prevSet;

                return `
        <th style="
            text-align:center;
            font-size:0.85em;
            ${isNewSet ? 'border-left:3px solid #888; padding-left:6px;' : ''}
        ">
            L${l.leg}
        </th>
    `;
}).join("")}
        </tr>
    `;
if (setGroups.length > 1) {
    html += `
<tr style="border-bottom:1px solid #444;">
    <th></th>
    ${setGroups.map((s, i) => `
        <th colspan="${s.count}" style="
            text-align:center;
            font-size:0.75em;
            color:#aaa;
            border-left:${i > 0 ? '3px solid #888' : 'none'};
        ">
           SET ${s.set + 1}
        </th>
    `).join("")}
</tr>
`;
}
            const playerNames = Object.keys(legs[0].players);

            playerNames.forEach(name => {
                html += `<tr style="border-top:1px solid #333;">`;

                // Name
                html += `
            <td style="
                text-align:left;
                padding-right:10px;
                text-transform:uppercase;
            ">
                ${name}
            </td>
        `;

                // Legs
                const setGroups = [];
                let currentSet = null;
                legs.forEach((l, i) => {
                    const data = l.players[name];

                    const prevSet = legs[i - 1]?.set;
                    const isNewSet = i > 0 && l.set !== prevSet;

                    if (data.type === "darts") {

                        legs.forEach((l, i) => {
                            if (l.set !== currentSet) {
                                setGroups.push({
                                    set: l.set,
                    start: i,
                    count: 1
                });
                currentSet = l.set;
            } else {
                setGroups[setGroups.length - 1].count++;
            }
});

        html += `
  <td style="
    text-align:center;
    font-weight:bold;
    ${isNewSet ? 'border-left:3px solid #888; padding-left:6px;' : ''}
"
title="${data.correctedFinish ? data.correctedDetail : ''}"
>
    <span style="
        display:inline-block;
        min-width:28px;
        padding:2px 6px;
        border-radius:50%;
        border:${data.correctedFinish ? '2px solid orange' : 'none'};
        color:${data.correctedFinish ? '#00e676' : '#00e676'};
    ">
        ${data.value}
    </span>
</td>
`;
    }
    else {
        html += `
<td style="
    text-align:center;
    color:#c0c0c0;
    opacity:0.8;
    ${isNewSet ? 'border-left:3px solid #888; padding-left:6px;' : ''}
">
    ${data.value}
</td>
`;
    }
});

                html += `</tr>`;





            });

            html += `</table>`;


            if (hasCorrections) {
                html += `
<div style="
    margin-top:10px;
    padding:8px 10px;
    font-size:0.85em;
    opacity:0.85;
    border-top:1px solid #333;
">
    <span style="color:orange; font-weight:bold;">${t("noticeTitle")}</span>
    ${t("noticeText")}
</div>
`;
            }
        }



        container.innerHTML = html;
        const target = document.querySelector('.chakra-card__body');

        if (target) {
            target.parentNode.insertBefore(container, target);
        } else {
            // Fallback falls UI noch nicht geladen
            document.body.prepend(container);
        }
    }

    function getGameId() {
        return window.location.href.match(/matches\/([a-z0-9-]+)/)?.[1];
    }



    function countCustomScores(match) {
        const result = {};

        // init
        match.players.forEach(p => {
            result[p.name.toUpperCase()] = {
                "90+": 0,
                "130+": 0,
                "171+": 0
            };
        });

        match.games?.forEach(game => {
            game.turns?.forEach(turn  => {

                const player = match.players
                .find(p => p.id === turn.playerId)
                ?.name.toUpperCase();

                const score =
                      turn.points ??
                      turn.score ??
                      turn.roundScore ??
                      0;

                if (!player) return;

                if (score === 180) {
                    // optional: falls du 180 separat zählen willst
                    // result[player]["180"]++;
                }
                else if (score >= 171 && score < 180) {
                    result[player]["171+"]++;
                }
                else if (score >= 130 && score < 171) {
                    result[player]["130+"]++;
                }
                else if (score >= 90 && score < 130) {
                    result[player]["90+"]++;
                }

            });
        });

        return result;
    }





    function countNoTripleOver100(match) {
        const result = {};
        match.players.forEach(p => result[p.name] = 0);

        match.games?.forEach(game => {

            const scorePerPlayer = {};
            match.players.forEach(p => {
                scorePerPlayer[p.id] = 501;
            });

            game.turns?.forEach(turn => {
                const pid = turn.playerId;

                let scored =
                    turn.points ??
                    turn.score ??
                    turn.roundScore ??
                    0;
                const player = match.players.find(p => p.id === pid)?.name;

                const currentScore = scorePerPlayer[pid];

                // 🔥 echte Würfe holen
                const throws = Array.isArray(turn.throws) ? turn.throws : [];

                // 🔥 NUR diese Triples zählen
                const allowedTriples = ["T20", "T19", "T18", "T17"];

                const hasTriple = throws.some(th =>
                                              allowedTriples.includes(th?.segment?.name)
                                             );

                // ✅ Deine finale Bedingung
                if (
                    currentScore > 100 &&
                    !hasTriple
                ) {
                    result[player]++;
                }

                // Score runterzählen (immer am Ende!)
                const score =
                      turn.points ??
                      turn.score ??
                      turn.roundScore ??
                      0;

                scorePerPlayer[pid] -= score;
                if (scorePerPlayer[pid] < 0) scorePerPlayer[pid] = 0;
            });
        });

        return result;
    }


    function countHighTriples(match) {
        const result = {};
        match.players.forEach(p => result[p.name.toUpperCase()] = 0);

        match.games?.forEach(game => {
            game.turns?.forEach(turn => {
                const player = match.players.find(p => p.id === turn.playerId)?.name.toUpperCase();

                const throws = turn.throws ?? [];

                throws.forEach(th => {
                    const name = th?.segment?.name;

                    if (["T20", "T19", "T18", "T17"].includes(name)) {
                        result[player]++;
                    }
                });
            });
        });

        return result;
    }



    function countNonDetectedThrows(match) {
        const result = {};

        // init
        match.players.forEach(p => {
            result[p.name.toUpperCase()] = 0;
        });

        match.games?.forEach(game => {
            game.turns?.forEach(turn => {
                const player = match.players.find(p => p.id === turn.playerId)?.name.toUpperCase();

                const throws = turn.throws ?? [];

                throws.forEach(th => {
                    if (th.entry !== "detected"
                        && th.entry !== "corrected_bouncer"
                        && th.entry !== "fill_miss"
                        && th.entry !== "referee_ai_corrected"
                        && th.entry !== "corrected_after_referee_ai"
                        && th.entry !== "referee_ai_confirmed") {
                        result[player]++;
                    }
                });
            });
        });

        return result;
    }








    function getHighFinishList(match) {
        const result = {};

        // init
        match.players.forEach(p => {
            result[p.name.toUpperCase()] = [];
        });

        match.games?.forEach(game => {

            const winnerId = game.winnerPlayerId;
            if (!winnerId) return;

            const playerName = match.players
            .find(p => p.id === winnerId)
            ?.name.toUpperCase();

            const turns = game.turns ?? [];

            // 👉 letzten Turn des Gewinners finden
            const lastTurn = [...turns]
            .reverse()
            .find(turn => turn.playerId === winnerId);

            if (!lastTurn) return;

            const points =
                  lastTurn.points ??
                  lastTurn.score ??
                  lastTurn.roundScore ??
                  0;

            // 👉 jetzt klappt’s garantiert
            if (points >= 90) {
                result[playerName].push(points);
            }
        });

        // sortieren
        Object.keys(result).forEach(name => {
            result[name].sort((a, b) => b - a);
        });

        return result;
    }




async function init() {
    const gameId = getGameId();
    if (!gameId) return;

    try {
        const match = await getMatchStats(gameId);

        // 🔥 Warten bis Daten wirklich da sind
        if (!match || !match.players || !match.matchStats) {
            return;
        }

        const stats = buildStats(match);

        // 👉 nur bei neuem Match loggen
        if (gameId !== currentGameId) {
            console.log("NEW MATCH:", gameId);
            currentGameId = gameId;
        }


// ❌ während Match → nichts anzeigen
if (!match.finishedAt) {
    document.querySelector('#ad-stats')?.remove();
    return;
}

// 🔥 WICHTIG: warten bis Games da sind
if (!match.games || match.games.length === 0) {
    console.log("Warte auf Legs...");
    return;
}

// ✅ jetzt erst rendern
render(stats, match);

    } catch (e) {
        console.error("Stats Error:", e);
    }
}


    (function () {
    const pushState = history.pushState;
    const replaceState = history.replaceState;

    function onChange() {
        console.log("URL CHANGE");
        currentGameId = null;

        // kleine Verzögerung → API ready
        setTimeout(init, 1000);
    }

    history.pushState = function () {
        pushState.apply(this, arguments);
        onChange();
    };

    history.replaceState = function () {
        replaceState.apply(this, arguments);
        onChange();
    };

    window.addEventListener("popstate", onChange);
})();

   setInterval(init, 2000);

})();