import {useEffect, useRef} from "react";

const max_x = 500;
const size = 24;

export function DrawGraph({root = []}) {
    const canvasRef = useRef(null);

    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 = scores[i].s1 + "-" + 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();
    };

    // 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 + 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);
            ctx.fillStyle = "#FF0000";
            printText(ctx, (match.c1FullName == null) ? "" : match.c1FullName,
                px - size * 2 - size * 8, py - size - (size * 1.5 / 2 | 0),
                size * 8, (size * 1.5 | 0), false, true);

            ctx.fillStyle = "#0000FF";
            printText(ctx, (match.c2FullName == null) ? "" : match.c2FullName,
                px - size * 2 - size * 8, py + size - (size * 1.5 / 2 | 0),
                size * 8, (size * 1.5 | 0), false, true);

            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);
            ctx.fillStyle = "#FF0000";
            printText(ctx, (match.c1FullName == null) ? "" : match.c1FullName,
                px - size * 2 - size * 8, py - size * 2 * death - (size * 1.5 / 2 | 0),
                size * 8, (size * 1.5 | 0), true, true);

            ctx.fillStyle = "#0000FF";
            printText(ctx, (match.c2FullName == null) ? "" : match.c2FullName,
                px - size * 2 - size * 8, py + size * 2 * death - (size * 1.5 / 2 | 0),
                size * 8, (size * 1.5 | 0), true, true);

            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, tree.left, px - size * 2 - size * 8, py - size * 2 * death, max_y);
        }
        if (tree.right != null) {
            drawNode(ctx, tree.right, px - size * 2 - size * 8, py + size * 2 * death, max_y);
        }
    };

    // Fonction pour déterminer le gagnant
    const win = (scores) => {
        let sum = 0;
        for (const score of scores) {
            if (score.s1 === -1000 || score.s2 === -1000) continue;
            if (score.s1 > score.s2) sum++;
            else if (score.s1 < score.s2) sum--;
        }
        return sum;
    };

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

        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";

        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 = win(node.data.scores) > 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, node, px, py, max_y);
            py = max_y.current + ((size * 2 * node.death() + ((size * 1.5 / 2) | 0)));
            px = maxx;
        }
    }, [root]);

    return <canvas ref={canvasRef} style={{border: "1px solid grey", marginTop: "10px"}} id="myCanvas"></canvas>;
}
