import {useEffect, useRef} from "react";
import {scorePrint} from "../../utils/Tools.js";
import {useCardsStatic} from "../../hooks/useCard.jsx";

const max_x = 500;

function getMousePos(canvas, evt) {
    const rect = canvas.getBoundingClientRect();
    return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
    };
}

export function DrawGraph({
                              root = [],
                              scrollRef = null,
                              onMatchClick = function (rect, match, comb) {
                              },
                              onClickVoid = function () {
                              },
                              matchSelect = null,
                              matchNext = null,
                              size = 24,
                              cards = []
                          }) {
    const canvasRef = useRef(null);
    const actionCanvasRef = useRef(null);
    const ctxARef = useRef(null);
    const actionMapRef = useRef({});
    const {getHeightCardForCombInMatch} = useCardsStatic(cards);

    const selectColor = "#30cc30";

    function getBounds(root) {
        let px = max_x;
        let py;
        let maxx, minx, miny, maxy

        function drawNode(tree, px, py) {
            let death = tree.death() - 1

            if (death === 0) {
                if (miny > py - size - ((size * 1.5 / 2) | 0)) miny = py - size - (size * 1.5 / 2) | 0;
                if (maxy < py + size + ((size * 1.5 / 2) | 0)) maxy = py + size + (size * 1.5 / 2) | 0;
            } else {
                if (miny > py - size * 2 * death - ((size * 1.5 / 2) | 0))
                    miny = py - size * 2 * death - ((size * 1.5 / 2) | 0);
                if (maxy < py + size * 2 * death + ((size * 1.5 / 2) | 0))
                    maxy = py + size * 2 * death + ((size * 1.5 / 2) | 0);
            }
            if (minx > px - size * 2 - size * 8) minx = px - size * 2 - size * 8;

            if (tree.left != null) drawNode(tree.left, px - size * 2 - size * 8, py - size * 2 * death);
            if (tree.right != null) drawNode(tree.right, px - size * 2 - size * 8, py + size * 2 * death);
        }

        if (root != null) {
            py = (size * 2 * root.at(0).death() + (((size * 1.5 / 2) | 0) + size) * root.at(0).death()) * 2;

            maxx = px;
            minx = px;
            miny = py - (size * 1.5 / 2) | 0;
            maxy = py + (size * 1.5 / 2) | 0;

            for (const node of root) {
                px = px - size * 2 - size * 8;
                if (minx > px) minx = px;

                drawNode(node, px, py);
                //graphics2D.drawRect(minx, miny, maxx - minx, maxy - miny);
                py = maxy + ((size * 2 * node.death() + ((size * 1.5 / 2) | 0)));
                px = maxx;
            }
        } else {
            minx = 0;
            maxx = 0;
            miny = 0;
            maxy = 0;
        }

        return [minx, maxx, miny, maxy];
    }

    // Fonction pour dessiner du texte avec gestion de la taille
    const printText = (ctx, s, x, y, width, height, lineG, lineD) => {
        ctx.save();
        ctx.translate(x, y);
        let tSize = 17;
        let ratioX = height * 1.0 / 20.0;
        ctx.font = "100 " + tSize + "px Arial";

        let mw = width - (ratioX * 2) | 0;
        if (ctx.measureText(s).width > mw) {
            do {
                tSize--;
                ctx.font = tSize + "px Arial";
            } while (ctx.measureText(s).width > mw && tSize > 10);

            if (ctx.measureText(s).width > mw) {
                let truncated = "";
                const words = s.split(" ");
                for (const word of words) {
                    if (ctx.measureText(truncated + word).width >= mw) {
                        truncated += "...";
                        break;
                    } else {
                        truncated += word + " ";
                    }
                }
                s = truncated;
            }
        }

        const text = ctx.measureText(s);
        let dx = (width - text.width) / 2;
        let dy = ((height - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);
        ctx.fillText(s, dx, dy, width - dy);
        ctx.restore();

        ctx.beginPath();
        if (lineD) {
            ctx.moveTo((ratioX * 2.5 + x + dx + text.width) | 0, y + height / 2);
            ctx.lineTo(x + width, y + height / 2);
        }
        if (lineG) {
            ctx.moveTo(x, y + height / 2);
            ctx.lineTo((dx + x - ratioX * 2.5) | 0, y + height / 2);
        }
        ctx.stroke();
    };

    // Fonction pour afficher les scores
    const printScores = (ctx, scores, px, py, scale) => {
        ctx.save();
        ctx.translate(px - size * 2, py - size * scale);
        ctx.font = "100 14px Arial";
        ctx.textBaseline = 'top';

        for (let i = 0; i < scores.length; i++) {
            const score = scorePrint(scores[i].s1) + "-" + scorePrint(scores[i].s2);
            const div = (scores.length <= 2) ? 2 : (scores.length >= 4) ? 4 : 3;
            const text = ctx.measureText(score);
            let dx = (size * 2 - text.width) / 2;
            let dy = ((size * 2 / div - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);

            ctx.fillStyle = '#ffffffdd';
            ctx.fillRect(dx, size * 2 * scale / div * i + dy, text.width, 14);
            ctx.fillStyle = "#000000";
            ctx.fillText(score, dx, size * 2 * scale / div * i + dy, size * 2);
        }
        ctx.restore();
    };

    const printCard = (ctx, pos, combId, match) => {
        const cards2 = getHeightCardForCombInMatch(combId, match)
        if (cards2 != null) {
            let oldColor = ctx.fillStyle;
            switch (cards2.type) {
                case "BLUE":
                    ctx.fillStyle = "#2e2efd";
                    break;
                case "YELLOW":
                    ctx.fillStyle = "#d8d800";
                    break;
                case "RED":
                    ctx.fillStyle = "#FF0000";
                    break;
                case "BLACK":
                    ctx.fillStyle = "#000000";
                    break;
                default:
                    ctx.fillStyle = "#FFFFFF00";
            }

            if (cards2.match === match.id) {
                ctx.beginPath();
                ctx.strokeStyle = ctx.fillStyle
                ctx.arc(pos.x + pos.width - 10, pos.y + 5, 5, 0, 2 * Math.PI);
                ctx.fill();
                ctx.stroke();
                ctx.strokeStyle = "#000000"
            } else
                ctx.fillRect(pos.x + pos.width - 18, pos.y - 5, 12, 12);
            ctx.fillStyle = oldColor;
        }
    }

    const newColor = () => {
        const letters = '0123456789ABCDEF'
        let color
        do {
            color = '#'
            for (let i = 0; i < 6; i++)
                color += letters[Math.floor(Math.random() * 16)]
        } while (actionMapRef.current[color] !== undefined)
        return color;
    }

    // Fonction pour dessiner un nœud
    const drawNode = (ctx, ctxA, tree, px, py, max_y) => {
        ctx.beginPath();
        ctx.moveTo(px, py);
        ctx.lineTo(px - size, py);
        ctx.stroke();

        let death = tree.death() - 1;
        let match = tree.data;

        if (death === 0) {
            ctx.beginPath();
            ctx.moveTo(px - size, py + size);
            ctx.lineTo(px - size, py - size);
            ctx.moveTo(px - size, py + size);
            ctx.lineTo(px - size * 2, py + size);
            ctx.moveTo(px - size, py - size);
            ctx.lineTo(px - size * 2, py - size);
            ctx.stroke();

            printScores(ctx, match.scores, px, py, 1);


            const pos = {x: px - size * 2 - size * 8, y: py - size - (size * 1.5 / 2 | 0), width: size * 8, height: (size * 1.5 | 0)}
            printCard(ctx, pos, match.c1, match)
            ctx.fillStyle = "#FF0000"
            printText(ctx, (match.c1FullName == null) ? "" : match.c1FullName, pos.x, pos.y, pos.width, pos.height, false, true)
            ctxA.fillStyle = newColor()
            ctxA.fillRect(pos.x, pos.y, pos.width, pos.height)
            actionMapRef.current[ctxA.fillStyle] = {type: 'match', rect: pos, match: match.id, comb: 1}

            const pos2 = {x: px - size * 2 - size * 8, y: py + size - (size * 1.5 / 2 | 0), width: size * 8, height: (size * 1.5 | 0)}
            printCard(ctx, pos2, match.c2, match)
            ctx.fillStyle = "#0000FF"
            printText(ctx, (match.c2FullName == null) ? "" : match.c2FullName, pos2.x, pos2.y, pos2.width, pos2.height, false, true)
            ctxA.fillStyle = newColor()
            ctxA.fillRect(pos2.x, pos2.y, pos2.width, pos2.height)
            actionMapRef.current[ctxA.fillStyle] = {type: 'match', rect: pos2, match: match.id, comb: 2}

            if (matchSelect && match.id === matchSelect) {
                ctx.strokeStyle = selectColor
                ctx.strokeRect(px - size * 2 - size * 8, py - size - (size * 1.5 / 2 | 0), size * 8, size * 2 + (size * 1.5 | 0))
                ctx.strokeStyle = "#000000"
            }

            if (matchNext && match.id === matchNext) {
                ctx.strokeStyle = selectColor
                ctx.setLineDash([15, 10])
                ctx.strokeRect(px - size * 2 - size * 8, py - size - (size * 1.5 / 2 | 0), size * 8, size * 2 + (size * 1.5 | 0))
                ctx.setLineDash([])
                ctx.strokeStyle = "#000000"
            }

            if (max_y.current < py + size + ((size * 1.5 / 2) | 0)) {
                max_y.current = py + size + (size * 1.5 / 2 | 0);
            }
        } else {
            ctx.beginPath();
            ctx.moveTo(px - size, py);
            ctx.lineTo(px - size, py + size * 2 * death);
            ctx.moveTo(px - size, py);
            ctx.lineTo(px - size, py - size * 2 * death);
            ctx.moveTo(px - size, py + size * 2 * death);
            ctx.lineTo(px - size * 2, py + size * 2 * death);
            ctx.moveTo(px - size, py - size * 2 * death);
            ctx.lineTo(px - size * 2, py - size * 2 * death);
            ctx.stroke();

            printScores(ctx, match.scores, px, py, 1.5);

            const pos = {x: px - size * 2 - size * 8, y: py - size * 2 * death - (size * 1.5 / 2 | 0), width: size * 8, height: (size * 1.5 | 0)}
            printCard(ctx, pos, match.c1, match)
            ctx.fillStyle = "#FF0000"
            printText(ctx, (match.c1FullName == null) ? "" : match.c1FullName, pos.x, pos.y, pos.width, pos.height, true, true)
            ctxA.fillStyle = newColor()
            ctxA.fillRect(pos.x, pos.y, pos.width, pos.height)
            actionMapRef.current[ctxA.fillStyle] = {type: 'match', rect: pos, match: match.id, comb: 1}

            const pos2 = {x: px - size * 2 - size * 8, y: py + size * 2 * death - (size * 1.5 / 2 | 0), width: size * 8, height: (size * 1.5 | 0)}
            printCard(ctx, pos2, match.c2, match)
            ctx.fillStyle = "#0000FF"
            printText(ctx, (match.c2FullName == null) ? "" : match.c2FullName, pos2.x, pos2.y, pos2.width, pos2.height, true, true)
            ctxA.fillStyle = newColor()
            ctxA.fillRect(pos2.x, pos2.y, pos2.width, pos2.height)
            actionMapRef.current[ctxA.fillStyle] = {type: 'match', rect: pos2, match: match.id, comb: 2}


            if (matchSelect && match.id === matchSelect) {
                ctx.strokeStyle = selectColor
                ctx.strokeRect(px - size * 2 - size * 8, py - size * 2 * death - (size * 1.5 / 2 | 0), size * 8,
                    py + size * 2 * death - (size * 1.5 / 2 | 0) - (py - size * 2 * death - (size * 1.5 / 2 | 0)) + (size * 1.5 | 0))
                ctx.strokeStyle = "#000000"
            }

            if (matchNext && match.id === matchNext) {
                ctx.strokeStyle = selectColor
                ctx.setLineDash([15, 10])
                ctx.strokeRect(px - size * 2 - size * 8, py - size * 2 * death - (size * 1.5 / 2 | 0), size * 8,
                    py + size * 2 * death - (size * 1.5 / 2 | 0) - (py - size * 2 * death - (size * 1.5 / 2 | 0)) + (size * 1.5 | 0))
                ctx.setLineDash([])
                ctx.strokeStyle = "#000000"
            }

            if (max_y.current < py + size * 2 * death + ((size * 1.5 / 2) | 0)) {
                max_y.current = py + size * 2 * death + ((size * 1.5 / 2 | 0));
            }
        }

        if (tree.left != null) {
            drawNode(ctx, ctxA, tree.left, px - size * 2 - size * 8, py - size * 2 * death, max_y);
        }
        if (tree.right != null) {
            drawNode(ctx, ctxA, tree.right, px - size * 2 - size * 8, py + size * 2 * death, max_y);
        }
    };

    // Effet pour dessiner le graphique
    useEffect(() => {
        if (root.length === 0) return;

        // Dessiner sur le canvas principal
        const canvas = canvasRef.current;
        const ctx = canvas.getContext("2d");
        const [minx, maxx, miny, maxy] = getBounds(root);

        canvas.width = maxx - minx;
        canvas.height = maxy - miny;
        ctx.translate(-minx, -miny);
        ctx.fillStyle = "#000000";
        ctx.lineWidth = 2;
        ctx.strokeStyle = "#000000";

        // Dessiner sur le canvas d'action
        const actionCanvas = actionCanvasRef.current;
        const ctxA = actionCanvas.getContext("2d", {willReadFrequently: true});
        ctxARef.current = ctxA;

        actionCanvas.width = maxx - minx;
        actionCanvas.height = maxy - miny;
        ctxA.translate(-minx, -miny);
        ctxA.fillStyle = "#000000";
        ctxA.lineWidth = 2;
        ctxA.strokeStyle = "#000000";

        actionMapRef.current = {};

        let px = maxx;
        let py;
        const max_y = {current: 0};

        py = (size * 2 * root[0].death() + (((size * 1.5 / 2) | 0) + size) * root[0].death()) * 2;
        max_y.current = py + (size * 1.5 / 2 | 0);
        for (const node of root) {
            let win_name = "";
            if (node.data.end) {
                win_name = node.data.win > 0
                    ? (node.data.c1FullName === null ? "???" : node.data.c1FullName)
                    : (node.data.c2FullName === null ? "???" : node.data.c2FullName);
            }

            ctx.fillStyle = "#18A918";
            printText(ctx, win_name,
                px - size * 2 - size * 8, py - ((size * 1.5 / 2) | 0),
                size * 8, (size * 1.5 | 0), true, false);

            px = px - size * 2 - size * 8;
            drawNode(ctx, ctxA, node, px, py, max_y);
            py = max_y.current + ((size * 2 * node.death() + ((size * 1.5 / 2) | 0)));
            px = maxx;
        }

        for (const color in actionMapRef.current) {
            const old = actionMapRef.current[color]
            if (old.rect == null) continue;
            actionMapRef.current[color] = {
                ...old,
                rect: {x: old.rect.x - minx, y: old.rect.y - miny + 10, width: old.rect.width, height: old.rect.height}
            };
        }
    }, [root]);

    useEffect(() => {
        let isDownScroll = false
        let downColor = undefined
        let startX
        let scrollLeft

        const mousedown = (e) => {
            const pos = getMousePos(canvasRef.current, e)
            const pixel = ctxARef.current.getImageData(pos.x, pos.y, 1, 1).data

            downColor = (pixel[3] === 0) ? undefined : `#${((1 << 24) + (pixel[0] << 16) + (pixel[1] << 8) + pixel[2]).toString(16).slice(1)}`

            if (downColor === undefined)
                onClickVoid()

            isDownScroll = downColor === undefined
            startX = e.pageX - scrollRef.current.offsetLeft
            scrollLeft = scrollRef.current.scrollLeft
        }

        const mouseleave = () => {
            isDownScroll = false
            downColor = undefined
        }

        const mouseup = (e) => {
            if (isDownScroll || downColor === undefined) {
                isDownScroll = false
                return
            }

            const pos = getMousePos(canvasRef.current, e)
            const pixel = ctxARef.current.getImageData(pos.x, pos.y, 1, 1).data
            const upColor = `#${((1 << 24) + (pixel[0] << 16) + (pixel[1] << 8) + pixel[2]).toString(16).slice(1)}`

            if (upColor === downColor) {
                const action = actionMapRef.current[downColor]
                if (action.type === 'match')
                    onMatchClick(action.rect, action.match, action.comb);
            }
        }

        const mousemove = (e) => {
            if (!isDownScroll) return
            e.preventDefault()
            const x = e.pageX - scrollRef.current.offsetLeft
            const walk = (x - startX) // Ajuste la vitesse de défilement
            scrollRef.current.scrollLeft = scrollLeft - walk
        }

        if (scrollRef) {
            canvasRef.current.addEventListener("mousedown", mousedown)
            canvasRef.current.addEventListener("mouseleave", mouseleave)
            canvasRef.current.addEventListener("mouseup", mouseup)
            canvasRef.current.addEventListener("mousemove", mousemove)
        }

        return () => {
            if (canvasRef && canvasRef.current) {
                canvasRef.current.removeEventListener("mousedown", mousedown)
                canvasRef.current.removeEventListener("mouseleave", mouseleave)
                canvasRef.current.removeEventListener("mouseup", mouseup)
                canvasRef.current.removeEventListener("mousemove", mousemove)
            }
        }
    }, [onMatchClick, onClickVoid]);

    return <div style={{position: "relative"}}>
        <canvas ref={actionCanvasRef} style={{border: "1px solid grey", marginTop: "10px", position: "absolute", top: 0, left: 0, opacity: 0}}
                id="myCanvas2"></canvas>
        <canvas ref={canvasRef} style={{border: "1px solid grey", marginTop: "10px", position: "relative", opacity: 1}} id="myCanvas"></canvas>
    </div>
}


export function drawGraphForPdf(root = [], size = 14, cards = []) {
    const {getHeightCardForCombInMatch} = useCardsStatic(cards);
    const sizeY = size * 0.5;

    function getBounds(root) {
        let px = max_x;
        let py;
        let maxx, minx, miny, maxy

        function drawNode(tree, px, py) {
            let death = tree.death() - 1

            if (death === 0) {
                if (miny > py - sizeY - ((sizeY * 1.5 / 2) | 0)) miny = py - sizeY - (sizeY * 1.5 / 2) | 0;
                if (maxy < py + sizeY + ((sizeY * 1.5 / 2) | 0)) maxy = py + sizeY + (sizeY * 1.5 / 2) | 0;
            } else {
                if (miny > py - sizeY * 2 * death - ((sizeY * 1.5 / 2) | 0))
                    miny = py - sizeY * 2 * death - ((sizeY * 1.5 / 2) | 0);
                if (maxy < py + sizeY * 2 * death + ((sizeY * 1.5 / 2) | 0))
                    maxy = py + sizeY * 2 * death + ((sizeY * 1.5 / 2) | 0);
            }
            if (minx > px - size * 2 - size * 8) minx = px - size * 2 - size * 8;

            if (tree.left != null) drawNode(tree.left, px - size * 2 - size * 8, py - sizeY * 2 * death);
            if (tree.right != null) drawNode(tree.right, px - size * 2 - size * 8, py + sizeY * 2 * death);
        }

        if (root != null) {
            py = (sizeY * 2 * root.at(0).death() + (((sizeY * 1.5 / 2) | 0) + sizeY) * root.at(0).death()) * 2;

            maxx = px;
            minx = px;
            miny = py - (sizeY * 1.5 / 2) | 0;
            maxy = py + (sizeY * 1.5 / 2) | 0;

            for (const node of root) {
                px = px - size * 2 - size * 8;
                if (minx > px) minx = px;

                drawNode(node, px, py);
                //graphics2D.drawRect(minx, miny, maxx - minx, maxy - miny);
                py = maxy + ((sizeY * 2 * node.death() + ((sizeY * 1.5 / 2) | 0)));
                px = maxx;
            }
        } else {
            minx = 0;
            maxx = 0;
            miny = 0;
            maxy = 0;
        }

        return [minx, maxx, miny, maxy];
    }

    // Fonction pour dessiner du texte avec gestion de la taille
    const printText = (ctx, s, x, y, width, height, lineG, lineD) => {
        ctx.save();
        ctx.translate(x, y);
        let tSize = 17;
        let ratioX = height * 1.0 / 20.0;
        ctx.font = "100 " + tSize + "px Arial";

        let mw = width - (ratioX * 2) | 0;
        if (ctx.measureText(s).width > mw) {
            do {
                tSize--;
                ctx.font = tSize + "px Arial";
            } while (ctx.measureText(s).width > mw && tSize > 10);

            if (ctx.measureText(s).width > mw) {
                let truncated = "";
                const words = s.split(" ");
                for (const word of words) {
                    if (ctx.measureText(truncated + word).width >= mw) {
                        truncated += "...";
                        break;
                    } else {
                        truncated += word + " ";
                    }
                }
                s = truncated;
            }
        }

        const text = ctx.measureText(s);
        let dx = (width - text.width) / 2;
        let dy = ((height - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);
        ctx.fillText(s, dx, dy, width - dy);
        ctx.restore();

        ctx.beginPath();
        if (lineD) {
            ctx.moveTo((ratioX * 2.5 + x + dx + text.width) | 0, y + height / 2);
            ctx.lineTo(x + width, y + height / 2);
        }
        if (lineG) {
            ctx.moveTo(x, y + height / 2);
            ctx.lineTo((dx + x - ratioX * 2.5) | 0, y + height / 2);
        }
        ctx.stroke();
    };

    // Fonction pour afficher les scores
    const printScores = (ctx, scores, px, py, scale) => {
        ctx.save();
        ctx.translate(px - size * 2, py - size * scale);
        ctx.font = "100 14px Arial";
        ctx.textBaseline = 'top';

        for (let i = 0; i < scores.length; i++) {
            const score = scorePrint(scores[i].s1) + "-" + scorePrint(scores[i].s2);
            const div = (scores.length <= 2) ? 2 : (scores.length >= 4) ? 4 : 3;
            const text = ctx.measureText(score);
            let dx = (size * 2 - text.width) / 2;
            let dy = ((size * 2 / div - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);

            ctx.fillStyle = '#ffffffdd';
            ctx.fillRect(dx, size * 2 * scale / div * i + dy, text.width, 14);
            ctx.fillStyle = "#000000";
            ctx.fillText(score, dx, size * 2 * scale / div * i + dy, size * 2);
        }
        ctx.restore();
    };

    const printCard = (ctx, pos, combId, match) => {
        const cards2 = getHeightCardForCombInMatch(combId, match)
        if (cards2 != null) {
            let oldColor = ctx.fillStyle;
            switch (cards2.type) {
                case "BLUE":
                    ctx.fillStyle = "#2e2efd";
                    break;
                case "YELLOW":
                    ctx.fillStyle = "#d8d800";
                    break;
                case "RED":
                    ctx.fillStyle = "#FF0000";
                    break;
                case "BLACK":
                    ctx.fillStyle = "#000000";
                    break;
                default:
                    ctx.fillStyle = "#FFFFFF00";
            }

            if (cards2.match === match.id) {
                ctx.beginPath();
                ctx.strokeStyle = ctx.fillStyle
                ctx.arc(pos.x + pos.width - 10, pos.y + 5, 5, 0, 2 * Math.PI);
                ctx.fill();
                ctx.stroke();
                ctx.strokeStyle = "#000000"
            } else
                ctx.fillRect(pos.x + pos.width - 18, pos.y - 5, 12, 12);
            ctx.fillStyle = oldColor;
        }
    }

    // Fonction pour dessiner un nœud
    const drawNode = (ctx, tree, px, py, max_y) => {
        ctx.beginPath();
        ctx.moveTo(px, py);
        ctx.lineTo(px - size, py);
        ctx.stroke();

        let death = tree.death() - 1;
        let match = tree.data;

        if (death === 0) {
            ctx.beginPath();
            ctx.moveTo(px - size, py + sizeY);
            ctx.lineTo(px - size, py - sizeY);
            ctx.moveTo(px - size, py + sizeY);
            ctx.lineTo(px - size * 2, py + sizeY);
            ctx.moveTo(px - size, py - sizeY);
            ctx.lineTo(px - size * 2, py - sizeY);
            ctx.stroke();

            printScores(ctx, match.scores, px, py, 1);


            const pos = {x: px - size * 2 - size * 8, y: py - sizeY - (sizeY * 1.5 / 2 | 0), width: size * 8, height: (sizeY * 1.5 | 0)}
            printCard(ctx, pos, match.c1, match)
            ctx.fillStyle = "#FF0000"
            printText(ctx, (match.c1FullName == null) ? "" : match.c1FullName, pos.x, pos.y, pos.width, pos.height, false, true)

            const pos2 = {x: px - size * 2 - size * 8, y: py + sizeY - (sizeY * 1.5 / 2 | 0), width: size * 8, height: (sizeY * 1.5 | 0)}
            printCard(ctx, pos2, match.c2, match)
            ctx.fillStyle = "#0000FF"
            printText(ctx, (match.c2FullName == null) ? "" : match.c2FullName, pos2.x, pos2.y, pos2.width, pos2.height, false, true)

            if (max_y.current < py + sizeY + ((sizeY * 1.5 / 2) | 0)) {
                max_y.current = py + sizeY + (sizeY * 1.5 / 2 | 0);
            }
        } else {
            ctx.beginPath();
            ctx.moveTo(px - size, py);
            ctx.lineTo(px - size, py + sizeY * 2 * death);
            ctx.moveTo(px - size, py);
            ctx.lineTo(px - size, py - sizeY * 2 * death);
            ctx.moveTo(px - size, py + sizeY * 2 * death);
            ctx.lineTo(px - size * 2, py + sizeY * 2 * death);
            ctx.moveTo(px - size, py - sizeY * 2 * death);
            ctx.lineTo(px - size * 2, py - sizeY * 2 * death);
            ctx.stroke();

            printScores(ctx, match.scores, px, py, 1.5);

            const pos = {x: px - size * 2 - size * 8, y: py - sizeY * 2 * death - (sizeY * 1.5 / 2 | 0), width: size * 8, height: (sizeY * 1.5 | 0)}
            printCard(ctx, pos, match.c1, match)
            ctx.fillStyle = "#FF0000"
            printText(ctx, (match.c1FullName == null) ? "" : match.c1FullName, pos.x, pos.y, pos.width, pos.height, true, true)

            const pos2 = {x: px - size * 2 - size * 8, y: py + sizeY * 2 * death - (sizeY * 1.5 / 2 | 0), width: size * 8, height: (sizeY * 1.5 | 0)}
            printCard(ctx, pos2, match.c2, match)
            ctx.fillStyle = "#0000FF"
            printText(ctx, (match.c2FullName == null) ? "" : match.c2FullName, pos2.x, pos2.y, pos2.width, pos2.height, true, true)

            if (max_y.current < py + sizeY * 2 * death + ((sizeY * 1.5 / 2) | 0)) {
                max_y.current = py + sizeY * 2 * death + ((sizeY * 1.5 / 2 | 0));
            }
        }

        if (tree.left != null) {
            drawNode(ctx, tree.left, px - size * 2 - size * 8, py - sizeY * 2 * death, max_y);
        }
        if (tree.right != null) {
            drawNode(ctx, tree.right, px - size * 2 - size * 8, py + sizeY * 2 * death, max_y);
        }
    };

    // Dessiner sur le canvas principal
    const canvas = document.createElement('canvas');
    canvas.id = "myCanvas";
    canvas.style.border = "1px solid grey";
    canvas.style.marginTop = "10px";

    const ctx = canvas.getContext("2d");

    const [minx, maxx, miny, maxy] = getBounds(root);
    canvas.width = maxx - minx;
    canvas.height = maxy - miny;
    ctx.translate(-minx, -miny);
    ctx.fillStyle = "#000000";
    ctx.lineWidth = 2;
    ctx.strokeStyle = "#000000";

    let px = maxx;
    let py;
    const max_y = {current: 0};

    py = (sizeY * 2 * root[0].death() + (((sizeY * 1.5 / 2) | 0) + sizeY) * root[0].death()) * 2;
    max_y.current = py + (sizeY * 1.5 / 2 | 0);
    for (const node of root) {
        let win_name = "";
        if (node.data.end) {
            win_name = node.data.win > 0
                ? (node.data.c1FullName === null ? "???" : node.data.c1FullName)
                : (node.data.c2FullName === null ? "???" : node.data.c2FullName);
        }

        ctx.fillStyle = "#18A918";
        printText(ctx, win_name,
            px - size * 2 - size * 8, py - ((sizeY * 1.5 / 2) | 0),
            size * 8, (sizeY * 1.5 | 0), true, false);

        px = px - size * 2 - size * 8;
        drawNode(ctx, node, px, py, max_y);
        py = max_y.current + ((sizeY * 2 * node.death() + ((sizeY * 1.5 / 2) | 0)));
        px = maxx;
    }

    return canvas;
}
