import React, {useEffect, useId, useRef, useState} from "react";
import {useRequestWS, useWS} from "../../../hooks/useWS.jsx";
import {LoadingProvider, useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
import {toast} from "react-toastify";
import {build_tree, from_sendTree, resize_tree} from "../../../utils/TreeUtils.js"
import {ConfirmDialog} from "../../../components/ConfirmDialog.jsx";
import {CategoryContent} from "./CategoryAdminContent.jsx";
import {exportOBSConfiguration} from "../../../hooks/useOBS.jsx";
import {createPortal} from "react-dom";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {SimpleIconsOBS} from "../../../assets/SimpleIconsOBS.ts";
import JSZip from "jszip";
import {detectOptimalBackground} from "../../../components/SmartLogoBackground.jsx";
import {faFile, faGlobe, faPrint, faTableCellsLarge, faTrash} from "@fortawesome/free-solid-svg-icons";
import {Trans, useTranslation} from "react-i18next";
import i18n from "i18next";
import {getToastMessage, toDataURL, win_end} from "../../../utils/Tools.js";
import {copyStyles} from "../../../utils/copyStyles.js";
import {StateWindow} from "./StateWindow.jsx";
import {CombName, useCombs} from "../../../hooks/useComb.jsx";
import {useCards, useCardsDispatch} from "../../../hooks/useCard.jsx";
import {ListPresetSelect} from "../../../components/cm/ListPresetSelect.jsx";
import {AutoNewCatModalContent, AutoNewCatSModalContent} from "../../../components/cm/AutoCatModalContent.jsx";
import {makePDF} from "../../../utils/cmPdf.js";

const vite_url = import.meta.env.VITE_URL;

export function CMAdmin({compUuid}) {
    const [catId, setCatId] = useState(null);
    const [cat, setCat] = useState(null);
    const menuActions = useRef({});
    const {dispatch} = useWS();

    useEffect(() => {
        const categoryListener = ({data}) => {
            if (!cat || data.id !== cat.id)
                return
            setCat(cat_ => ({
                ...cat_,
                name: data.name,
                liceName: data.liceName,
                type: data.type,
                treeAreClassement: data.treeAreClassement,
                fullClassement: data.fullClassement,
                preset: data.preset,
            }))
        }
        dispatch({type: 'addListener', payload: {callback: categoryListener, code: 'sendCategory'}})
        return () => dispatch({type: 'removeListener', payload: categoryListener})
    }, [cat]);

    return <>
        <div className="card">
            <div className='card-header'>
                <CategoryHeader cat={cat} setCatId={setCatId} menuActions={menuActions}/>
            </div>

            <div className="card-body">
                <LoadingProvider>
                    <div className="row">
                        <CategoryContent cat={cat} catId={catId} setCat={setCat} menuActions={menuActions}/>
                    </div>
                </LoadingProvider>
            </div>
            <Menu menuActions={menuActions} compUuid={compUuid}/>
        </div>
    </>
}

let tto = [];

function resizeImageWithOptimalBackground(blob) {
    return new Promise(async (resolve) => {
        const background = await detectOptimalBackground(blob);
        const imgUrl = URL.createObjectURL(blob);
        const img = new Image();
        img.crossOrigin = "anonymous";
        img.onload = () => {
            const canvas = document.createElement('canvas');
            canvas.width = 1080;
            canvas.height = 1080;
            const ctx = canvas.getContext('2d');

            // Dessiner l'image centrée
            const scale = Math.min(1080 / img.width, 1080 / img.height);
            const newWidth = img.width * scale;
            const newHeight = img.height * scale;
            const x = (1080 - newWidth) / 2;
            const y = (1080 - newHeight) / 2;

            ctx.filter = `drop-shadow(0 0 2rem ${background})`;
            ctx.drawImage(img, x, y, newWidth, newHeight);

            // Exporter en PNG
            canvas.toBlob((newBlob) => {
                resolve(newBlob);
                URL.revokeObjectURL(imgUrl);
            }, 'image/png', 1.0);
        };
        img.onerror = () => resolve(blob); // Retourne l'original en cas d'erreur
        img.src = imgUrl;
    });
}

async function downloadResourcesAsZip(resourceList) {
    const zip = new JSZip();
    const modal = new bootstrap.Modal(document.getElementById('progressModal'));
    const progressBar = document.getElementById('progressBar');
    const progressText = document.getElementById('progressText');
    let completed = 0;

    if (!resourceList.some(d => d.url === '/obs_template.json'))
        resourceList.push({url: '/obs_template.json', name: 'saf_obs_template.json'});

    // Afficher la modale
    modal.show();

    // Fonction pour télécharger une ressource et l'ajouter au ZIP
    const addResourceToZip = async (data) => {
        try {
            const response = await fetch(data.url);
            if (!response.ok) {
                if (response.status === 404) {
                    return {success: false, filename: data.name || data.url.split('/').pop()};
                }
                // noinspection ExceptionCaughtLocallyJS
                throw new Error(`Erreur HTTP: ${response.status}`);
            }
            const blob = await response.blob();
            const filename = data.name || data.url.split('/').pop();
            const format = filename.split('.').pop().toLowerCase();

            if (['png', 'jpg', 'jpeg', 'svg'].includes(format)) {
                const resizedBlob = await resizeImageWithOptimalBackground(blob);
                const pngFilename = filename.replace(/\.[^/.]+$/, ".png");
                zip.file(pngFilename, resizedBlob);
                return {success: true, pngFilename};
            } else {
                zip.file(filename, blob);
                return {success: true, filename};
            }
        } catch (error) {
            console.error(`Impossible d'ajouter ${data.url} au ZIP:`, error);
            return {success: false, filename: data.name || data.url.split('/').pop()};
        }
    };

    // Télécharger toutes les ressources et mettre à jour la progression
    await Promise.all(
        resourceList.map(async (data) => {
            const result = await addResourceToZip(data);
            completed++;
            const progress = Math.round((completed / resourceList.length) * 100);
            progressBar.style.width = `${progress}%`;
            progressText.textContent = `${i18n.t('téléchargement')} (${completed}/${resourceList.length}) : ${result.filename}`;
            return result;
        })
    );

    // Générer le ZIP et déclencher le téléchargement
    const zipBlob = await zip.generateAsync({type: 'blob'});
    const zipUrl = URL.createObjectURL(zipBlob);
    const a = document.createElement('a');
    a.href = zipUrl;
    a.download = 'ressources.zip';
    a.click();
    URL.revokeObjectURL(zipUrl);

    // Fermer la modale
    modal.hide();
    progressText.textContent = i18n.t('téléchargementTerminé!');
}

const windowName = "FFSAFTableStateWindow";

function Menu({menuActions, compUuid}) {
    const e = document.getElementById("actionMenu")
    const longPress = useRef({time: null, timer: null, button: null});
    const obsModal = useRef(null);
    const teamCardModal = useRef(null);
    const printModal = useRef(null);
    const {t} = useTranslation("cm");

    const [showStateWin, setShowStateWin] = useState(false)
    const externalWindow = useRef(null)
    const containerEl = useRef(document.createElement("div"))

    for (const x of tto)
        x.dispose();
    const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip2"]')
    tto = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))

    const longTimeAction = (button) => {
        if (button === "obs") {
            obsModal.current.click();
        }
    }

    useEffect(() => {
        if (sessionStorage.getItem(windowName + "_open") === "true") {
            handleStateWin();
        }
    }, []);

    const handleStateWin = __ => {
        if (showStateWin === false || !externalWindow.current || externalWindow.current.closed) {
            externalWindow.current = window.open("", windowName, "width=800,height=600,left=200,top=200")
            externalWindow.current.document.body.innerHTML = ""
            externalWindow.current.document.body.appendChild(containerEl.current)
            copyStyles(document, externalWindow.current.document)

            externalWindow.current.addEventListener("beforeunload", () => {
                setShowStateWin(false);
                externalWindow.current.close();
                externalWindow.current = null;
                sessionStorage.removeItem(windowName + "_open");
            });
            setShowStateWin(true);
            sessionStorage.setItem(windowName + "_open", "true");
        } else {
            externalWindow.current.focus();
        }
    }

    const longPressDown = (button) => {
        longPress.current.button = button;
        longPress.current.time = new Date();
        longPress.current.timer = setTimeout(() => {
            longTimeAction(button);

            longPress.current.time = null;
            longPress.current.button = null;
        }, 1000);
    }

    const longPressUp = (button) => {
        clearTimeout(longPress.current.timer);

        if (longPress.current.time) {
            const diff = new Date() - longPress.current.time;
            if (longPress.current.button === button) {
                if (diff >= 1000) {
                    longTimeAction(button);
                } else {
                    if (button === "obs") {
                        downloadResourcesAsZip(menuActions.current.resourceList || [])
                            .then(__ => console.log("Ressources téléchargées"));
                    } else if (button === "cards") {
                        teamCardModal.current.click();
                    }
                }
            }

            longPress.current.time = null;
            longPress.current.button = null;
        }
    }

    const handleOBSSubmit = (e) => {
        e.preventDefault();
        const form = e.target;
        const adresse = form[0].value;
        const password = form[1].value;
        const assets_dir = form[2].value;

        exportOBSConfiguration(adresse, password, assets_dir)
    }

    const copyScriptToClipboard = () => {
        // noinspection JSFileReferences
        navigator.clipboard.writeText(`
<div id='safca_api_data'></div>
<script type="module">
    import {initCompetitionApi} from '${vite_url}/competition.js';
    initCompetitionApi("${vite_url}/api/public/result/${compUuid}", "${vite_url}")
</script>`
        ).then(() => {
            toast.success(t('texteCopiéDansLePresse'));
        }).catch(err => {
            toast.error(t('erreurLorsDeLaCopieDansLePresse') + err);
        });
    }

    if (!e)
        return <></>;
    return <>
        {createPortal(
            <>
                <div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
                <FontAwesomeIcon icon={faFile} size="xl"
                                 style={{color: "#6c757d", cursor: "pointer"}}
                                 onMouseDown={() => longPressDown("cards")}
                                 onMouseUp={() => longPressUp("cards")}
                                 data-bs-toggle="tooltip2" data-bs-placement="top"
                                 data-bs-title={t("carton")}/>
                <FontAwesomeIcon icon={faPrint} size="xl"
                                 style={{color: "#6c757d", cursor: "pointer"}}
                                 onClick={() => printModal.current.click()}
                                 data-bs-toggle="tooltip2" data-bs-placement="top"
                                 data-bs-title={t('imprimer')}/>
                <FontAwesomeIcon icon={SimpleIconsOBS} size="xl"
                                 style={{color: "#6c757d", cursor: "pointer"}}
                                 onMouseDown={() => longPressDown("obs")}
                                 onMouseUp={() => longPressUp("obs")}
                                 data-bs-toggle="tooltip2" data-bs-placement="top"
                                 data-bs-title={t('ttm.admin.obs')}/>
                <FontAwesomeIcon icon={faGlobe} size="xl"
                                 style={{color: "#6c757d", cursor: "pointer"}}
                                 onClick={() => copyScriptToClipboard()}
                                 data-bs-toggle="tooltip2" data-bs-placement="top"
                                 data-bs-title={t('ttm.admin.scripte')}/>
                <FontAwesomeIcon icon={faTableCellsLarge} size="xl"
                                 style={{color: showStateWin ? "#00c700" : "#6c757d", cursor: "pointer", marginRight: "0.25em"}}
                                 onClick={handleStateWin}
                                 data-bs-toggle="tooltip2" data-bs-placement="top" data-bs-title={t('etatDesTablesDeMarque')}/>
            </>, document.getElementById("actionMenu"))}
        {externalWindow.current && createPortal(<StateWindow document={externalWindow.current.document}/>, containerEl.current)}

        <button ref={obsModal} type="button" className="btn btn-link" data-bs-toggle="modal" data-bs-target="#OBSModal" style={{display: 'none'}}>
            Launch OBS Modal
        </button>
        <div className="modal fade" id="OBSModal" tabIndex="-1" aria-labelledby="OBSModalLabel" aria-hidden="true">
            <div className="modal-dialog">
                <div className="modal-content">
                    <div className="modal-header">
                        <h5 className="modal-title">{t('configurationObs')}</h5>
                        <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <form onSubmit={handleOBSSubmit}>
                        <div className="modal-body">
                            <strong>{t('config.obs.warn1')}</strong>
                            <div className="input-group mb-3">
                                <span className="input-group-text">{t('adresseDuServeur')}</span>
                                <input type="text" className="form-control" placeholder="ws://127.0.0.1:4455/" aria-label=""
                                       defaultValue={"ws://127.0.0.1:4455/"}/>
                                <span className="input-group-text">/</span>
                            </div>
                            <div className="input-group mb-3">
                                <span className="input-group-text">{t('config.obs.motDePasseDuServeur')}</span>
                                <input type="password" className="form-control" placeholder="12345" aria-label=""
                                       defaultValue={""}/>
                            </div>
                            <div className="input-group mb-3">
                                <span className="input-group-text">{t('config.obs.dossierDesResources')}</span>
                                <input type="text" className="form-control" placeholder="" aria-label="" required/>
                            </div>
                        </div>
                        <div className="modal-footer">
                            <button type="button" className="btn btn-secondary" data-bs-dismiss="modal">{t('fermer')}</button>
                            <button type="submit" className="btn btn-primary" data-bs-dismiss="modal">{t('exporter')}</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>

        <div className="modal fade" id="progressModal" tabIndex="-1" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
            <div className="modal-dialog">
                <div className="modal-content">
                    <div className="modal-header">
                        <h5 className="modal-title">{t('téléchargementEnCours')}</h5>
                        <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div className="modal-body">
                        <div className="progress">
                            <div id="progressBar" className="progress-bar" role="progressbar" style={{width: "0%"}}></div>
                        </div>
                        <div id="progressText" className="mt-2">{t('préparation...')}</div>
                    </div>
                </div>
            </div>
        </div>

        <button ref={teamCardModal} type="button" className="btn btn-link" data-bs-toggle="modal" data-bs-target="#TeamCardModal"
                style={{display: 'none'}}>
            Launch OBS Modal
        </button>
        <div className="modal modal-xl fade" id="TeamCardModal" tabIndex="-1" aria-labelledby="TeamCardModalLabel" aria-hidden="true">
            <div className="modal-dialog">
                <div className="modal-content">
                    <TeamCardModal/>
                </div>
            </div>
        </div>

        <button ref={printModal} type="button" className="btn btn-link" data-bs-toggle="modal" data-bs-target="#PrintModal"
                style={{display: 'none'}}>
            Launch printModal
        </button>
        <div className="modal fade" id="PrintModal" tabIndex="-1" aria-labelledby="PrintModalLabel" aria-hidden="true">
            <div className="modal-dialog">
                <div className="modal-content">
                    <PrintModal menuActions={menuActions}/>
                </div>
            </div>
        </div>
    </>
}

function PrintModal({menuActions}) {
    const [categorie, setCategorie] = useState(false);
    const [categorieEmpty, setCategorieEmpty] = useState(false);
    const [preset, setPreset] = useState(false);
    const [presetEmpty, setPresetEmpty] = useState(false);
    const [allCat, setAllCat] = useState(false);
    const [allCatEmpty, setAllCatEmpty] = useState(false);
    const [podium, setPodium] = useState(false);
    const [podiumRank, setPodiumRank] = useState(4);
    const [podiumClub, setPodiumClub] = useState(false);

    const [presetSelect, setPresetSelect] = useState(-1)

    const {sendRequest, welcomeData} = useWS();
    const {getComb} = useCombs();
    const {t} = useTranslation("cm");

    const podiumPromise = (podiumRank_) => {
        return sendRequest("getPodium", {}).then(data => {
            return [welcomeData?.name + " - " + t('podium'), [
                {type: "podium", params: ({data, maxRank: podiumRank_, minRank: Math.min(4, podiumRank_)})},
            ]];
        });
    }

    const podiumClubPromise = () => {
        return sendRequest("getPodiumClub", {}).then(data => {
            return [welcomeData?.name + " - " + t('classementDesClub', {ns: "result"}), [
                {type: "podiumClub", params: ({data})},
            ]];
        });
    }

    const print = (action) => {
        const pagesPromise = [];

        if (categorie && menuActions.printCategorie)
            pagesPromise.push(menuActions.printCategorie(categorieEmpty))

        if (preset && menuActions.printCategoriePreset)
            pagesPromise.push(menuActions.printCategoriePreset(presetEmpty, presetSelect))

        if (allCat && menuActions.printAllCategorie)
            pagesPromise.push(menuActions.printAllCategorie(categorieEmpty, welcomeData?.name + " - " + t('toutesLesCatégories')))

        if (podium)
            pagesPromise.push(podiumPromise(podiumRank));

        if (podiumClub)
            pagesPromise.push(podiumClubPromise());

        toast.promise(
            toDataURL("/Logo-FFSAF-2023.png").then(logo => {
                return Promise.allSettled(pagesPromise).then(results => {
                    const pages = [];
                    const names = [];
                    let errors = 0;

                    for (const result of results) {
                        if (result.status === "fulfilled") {
                            const [name, page, error] = result.value;
                            pages.push(...page);
                            names.push(name);
                            errors += error
                        } else if (result.status === "rejected") {
                            errors += 1;
                        }
                    }

                    if (errors > 0) {
                        toast.error(t('erreurGénérationPages', {count: errors}));
                    }

                    if (pages.length !== 0) {
                        makePDF(action, pages, names.join(" - "), welcomeData?.name, getComb, t, logo)
                    }
                })
            }), getToastMessage("toast.print", "cm"))
    }

    return <>
        <div className="modal-header">
            <h5 className="modal-title">{t('quoiImprimer?')}</h5>
            <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div className="modal-body">
            <div className="form-check">
                <input className="form-check-input" type="checkbox" checked={categorie} id="checkPrint"
                       onChange={e => setCategorie(e.target.checked)}/>
                <label className="form-check-label" htmlFor="checkPrint">{t('catégorieSélectionnée')}</label>
            </div>
            {categorie &&
                <div className="form-check" style={{marginLeft: "1em"}}>
                    <input className="form-check-input" type="checkbox" checked={categorieEmpty} id="checkPrint2"
                           onChange={e => setCategorieEmpty(e.target.checked)}/>
                    <label className="form-check-label" htmlFor="checkPrint2">{t('feuilleVierge')}</label>
                </div>}

            <div className="form-check">
                <input className="form-check-input" type="checkbox" checked={preset} id="checkPrint3"
                       onChange={e => setPreset(e.target.checked)}/>
                <label className="form-check-label" htmlFor="checkPrint3">{t('touteLaCatégorie')}</label>
            </div>
            {preset && <div style={{marginLeft: "1em"}}>
                <div className="form-check">
                    <input className="form-check-input" type="checkbox" checked={presetEmpty} id="checkPrint4"
                           onChange={e => setPresetEmpty(e.target.checked)}/>
                    <label className="form-check-label" htmlFor="checkPrint4">{t('feuilleVierge')}</label>
                </div>
                <ListPresetSelect value={presetSelect} onChange={setPresetSelect}/>
            </div>}

            <div className="form-check">
                <input className="form-check-input" type="checkbox" checked={allCat} id="checkPrint5"
                       onChange={e => setAllCat(e.target.checked)}/>
                <label className="form-check-label" htmlFor="checkPrint5">{t('toutesLesCatégories')}</label>
            </div>
            {allCat &&
                <div className="form-check" style={{marginLeft: "1em"}}>
                    <input className="form-check-input" type="checkbox" checked={allCatEmpty} id="checkPrint6"
                           onChange={e => setAllCatEmpty(e.target.checked)}/>
                    <label className="form-check-label" htmlFor="checkPrint6">{t('feuilleVierge')}</label>
                </div>}

            <div className="form-check">
                <input className="form-check-input" type="checkbox" checked={podium} id="checkPrint7"
                       onChange={e => setPodium(e.target.checked)}/>
                <label className="form-check-label" htmlFor="checkPrint7">{t('podium')}</label>
            </div>
            {podium &&
                <div style={{marginLeft: "1em"}}>
                    <label htmlFor="range3" className="form-label">{t('jusquauRang')} {podiumRank} </label>
                    <input type="range" className="form-range" min="1" max="20" step="1" id="range3" value={podiumRank}
                           onChange={e => setPodiumRank(Number(e.target.value))}/>
                </div>}

            <div className="form-check">
                <input className="form-check-input" type="checkbox" checked={podiumClub} id="checkPrint8"
                       onChange={e => setPodiumClub(e.target.checked)}/>
                <label className="form-check-label" htmlFor="checkPrint8">{t('classementDesClub', {ns: "result"})}</label>
            </div>
        </div>
        <div className="modal-footer">
            <button type="submit" className="btn btn-primary" data-bs-dismiss="modal" onClick={() => print("show")}>{t('afficher')}</button>
            <button type="submit" className="btn btn-primary" data-bs-dismiss="modal" onClick={() => print("download")}>{t('enregistrer')}</button>
            <button type="submit" className="btn btn-primary" data-bs-dismiss="modal" onClick={() => print("print")}>{t('imprimer')}</button>
            <button type="button" className="btn btn-secondary" data-bs-dismiss="modal">{t('fermer')}</button>
        </div>
    </>
}

function TeamCardModal() {
    const [club, setClub] = useState("")

    const {t} = useTranslation("cm");
    const {combs} = useCombs()
    const {sendRequest} = useWS()
    const {cards_t, cards_v} = useCards()
    const cardDispatch = useCardsDispatch();
    const {data} = useRequestWS("getAllForTeamNoDetail", {}, null);

    useEffect(() => {
        if (!data)
            return;
        for (const card of data) {
            cardDispatch({type: 'SET_TEAM_CARD', payload: card});
        }
    }, [data]);

    let clubList = [];
    if (combs != null) {
        clubList = Object.values(combs).map(d => d.club_str).filter((v, i, a) => v !== "" && v !== undefined && a.indexOf(v) === i);
    }

    const handleAdd = (e) => {
        e.preventDefault();
        toast.promise(sendRequest("applyTeamCards", {
                teamUuid: Object.values(combs).find(d => d.club_str === club)?.club_uuid,
                teamName: club,
                type: "YELLOW"
            }),
            getToastMessage("toast.card.team", "cm"))
            .then(() => {
            })
    }

    const GetCard = ({type}) => {
        if (!type)
            return <></>
        let bg = "";
        switch (type) {
            case "YELLOW":
                bg = " bg-warning";
                break;
            case "RED":
                bg = " bg-danger";
                break;
            case "BLACK":
                bg = " bg-dark text-white";
                break;
            case "BLUE":
                bg = " bg-primary text-white";
                break;
        }
        return <span className={"badge border border-light p-2" + bg}><span className="visually-hidden">card</span></span>
    }

    let cards = [...cards_t, ...cards_v].sort((a, b) => new Date(b.date) - new Date(a.date))
    return <>
        <div className="modal-header">
            <h5 className="modal-title">{t('carton')}</h5>
            <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div className="modal-body">
            <h5>{t('cartonDéquipe')}</h5>
            <div className="input-group mb-3">
                <label htmlFor="inputGroupSelect09" className="input-group-text">{t('club')}</label>
                <select id="inputGroupSelect09" className="form-select" value={club} onChange={(e) => setClub(e.target.value)}>
                    {clubList.sort((a, b) => a.localeCompare(b)).map((club, index) => (
                        <option key={index} value={club}>{club}</option>))}
                </select>
                <button className="btn btn-outline-primary" type="button" onClick={handleAdd}>{t("ajouter")}</button>
            </div>

            <h5>{t('listeDesCartons')}</h5>
            <table className="table">
                <thead>
                <tr>
                    <th scope="col">{t('date')}</th>
                    <th scope="col">{t('type')}</th>
                    <th scope="col">{t('couleur')}</th>
                    <th scope="col">{t('nom')}</th>
                    <th scope="col"></th>
                </tr>
                </thead>
                <tbody>
                {cards.map((card, index) => <tr key={index}>
                    <td scope="row">{new Date(card.date).toLocaleString()}</td>
                    {card.teamName ? <>
                        <td>{t('team')}</td>
                        <td><GetCard type={card.type}/></td>
                        <td>{card.teamName}</td>
                    </> : <>
                        <td>{card.teamCard ? "|-> " + t('team') : t('individuelle')} </td>
                        <td><GetCard type={card.type}/></td>
                        <td><CombName combId={card.comb}/></td>
                    </>}

                    <td style={{textAlign: "center", cursor: "pointer", color: "#ff1313"}} onClick={_ => {
                        if (confirm("Êtes-vous sûr de vouloir supprimer ce carton ?")) {
                            if (card.teamName) {
                                toast.promise(sendRequest("removeTeamCards", {
                                        teamUuid: card.teamUuid, teamName: card.teamName, type: card.type
                                    }),
                                    getToastMessage("toast.card.team", "cm"))
                                    .then(() => {
                                    })
                            } else {
                                sendRequest('sendCardRm', {matchId: card.match, combId: card.comb, type: card.type})
                                    .then(() => toast.success(t('cardRemoved')))
                                    .catch(err => toast.error(err))
                            }
                        }
                    }}><FontAwesomeIcon icon={faTrash}/></td>
                </tr>)}
                </tbody>
            </table>
        </div>
        <div className="modal-footer">
            <button type="button" className="btn btn-secondary" data-bs-dismiss="modal">{t('fermer')}</button>
        </div>
    </>
}

function CategoryHeader({cat, setCatId, menuActions}) {
    const setLoading = useLoadingSwitcher()
    const bthRef = useRef(null);
    const newBthRef = useRef(null);
    const confirmRef = useRef(null);
    const [modal, setModal] = useState({})
    const [confirm, setConfirm] = useState({})
    const {t} = useTranslation("cm");

    const {data: cats, setData: setCats} = useRequestWS('getAllCategory', {}, setLoading);
    const {dispatch} = useWS();

    useEffect(() => {
        const categoryListener = ({data}) => {
            setCats([
                ...cats.filter(c => c.id !== data.id),
                data
            ])
        }
        const sendAddCategory = ({data}) => {
            console.log("add cat", data);
            setCats([...cats, data])
        }
        const sendDelCategory = ({data}) => {
            setCatId(catId => {
                if (catId === data) return null;
                return catId;
            })
            setCats([...cats.filter(c => c.id !== data)])
        }
        dispatch({type: 'addListener', payload: {callback: categoryListener, code: 'sendCategory'}})
        dispatch({type: 'addListener', payload: {callback: sendAddCategory, code: 'sendAddCategory'}})
        dispatch({type: 'addListener', payload: {callback: sendDelCategory, code: 'sendDelCategory'}})
        return () => {
            dispatch({type: 'removeListener', payload: categoryListener})
            dispatch({type: 'removeListener', payload: sendAddCategory})
            dispatch({type: 'removeListener', payload: sendDelCategory})
        }
    }, [cats]);

    useEffect(() => {
        if (cats && cats.length > 0 && (!cat || (cats && !cats.find(c => c.id === cat.id)))) {
            setCatId(cats.sort((a, b) => a.name.localeCompare(b.name))[0].id);
        } else if (cats && cats.length === 0) {
            setModal({});
            bthRef.current.click();
        }
    }, [cats, cat]);

    const handleCatChange = (e) => {
        const selectedCatId = e.target.value;
        if (selectedCatId !== "-1") {
            setCatId(selectedCatId);
        } else { // New category
            newBthRef.current.click();
            e.target.value = cat?.id;
        }
    }

    return <div className="row">
        <div className="col-auto">
            <div className="input-group">
                <h5 style={{margin: "auto 0.5em auto 0"}}>{t('editionDeLaCatégorie')}</h5>
                <select className="form-select" onChange={handleCatChange} value={cat?.id || ""}>
                    {cats && cats.sort((a, b) => a.name.localeCompare(b.name)).map(c => (
                        <option key={c.id} value={c.id}>{c.name}</option>))}
                    {cats && <option value={-1}>{t('nouvelle...')}</option>}
                </select>
            </div>
        </div>
        <div className="col" style={{margin: "auto 0", textAlign: "center"}}>
            {cat &&
                <div>Type: {(cat.type & 1) !== 0 ? t('poule') : ""}{cat.type === 3 ? " & " : ""}{(cat.type & 2) !== 0 ? (cat.treeAreClassement ? t('classement') : t('tournois')) : ""} |
                    Zone: {cat.liceName}</div>}
        </div>
        <div className="col-auto">
            <button className="btn btn-primary float-end" onClick={() => {
                setModal(cat);
                bthRef.current.click();
            }} disabled={cat === null}>{t('modifier')}
            </button>
        </div>


        <button ref={bthRef} data-bs-toggle="modal" data-bs-target="#CategorieModal" style={{display: "none"}}>open</button>
        <div className="modal fade" id="CategorieModal" tabIndex="-1" aria-labelledby="CategorieModalLabel"
             aria-hidden="true">
            <div className="modal-dialog">
                <div className="modal-content">
                    <ModalContent state={modal} setCatId={setCatId} setConfirm={setConfirm} confirmRef={confirmRef}/>
                </div>
            </div>
        </div>

        <div className="modal fade" id="autoNewCatModal" aria-hidden="true" aria-labelledby="autoNewCatModalLabel" tabIndex="-1">
            <div className="modal-dialog modal-dialog-centered">
                <div className="modal-content">
                    <AutoNewCatModalContent/>
                </div>
            </div>
        </div>

        <div className="modal fade" id="autoNewCatsModal" aria-hidden="true" aria-labelledby="autoNewCatsModalLabel" tabIndex="-1">
            <div className="modal-dialog modal-dialog-centered">
                <div className="modal-content">
                    <AutoNewCatSModalContent/>
                </div>
            </div>
        </div>

        <button ref={confirmRef} data-bs-toggle="modal" data-bs-target="#confirm-dialog" style={{display: "none"}}>open</button>
        <ConfirmDialog id="confirm-dialog" onConfirm={confirm.confirm ? confirm.confirm : () => {
        }} onCancel={confirm.cancel ? confirm.cancel : () => {
        }} title={confirm ? confirm.title : ""} message={confirm ? confirm.message : ""}/>


        <button ref={newBthRef} data-bs-toggle="modal" data-bs-target="#newCatModal" style={{display: "none"}}>open</button>

        <div className="modal fade" id="newCatModal" tabIndex="-1" aria-labelledby="newCatModalLabel" aria-hidden="true">
            <div className="modal-dialog modal-dialog-centered">
                <div className="modal-content">
                    <div className="modal-header">
                        <h1 className="modal-title fs-5" id="newCatModalLabel">{t('ajouter')} {t('uneCatégorie')}</h1>
                        <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div className="modal-body text-center">
                        {t('modeDeCréation')} :
                        <div className="mb-2">
                            <button className="btn btn-primary" onClick={() => {
                                setModal({});
                                bthRef.current.click();
                                e.target.value = cat?.id;
                            }}>{t('personnaliser')}</button>
                        </div>
                        <div className="mb-2">
                            <button className="btn btn-primary" data-bs-target="#autoNewCatModal"
                                    data-bs-toggle="modal">{t('depuisUneCatégoriePrédéfinie')}</button>
                        </div>
                        <div className="mb-2">
                            <button className="btn btn-primary" data-bs-target="#autoNewCatsModal"
                                    data-bs-toggle="modal">{t('créerToutesLesCatégories')}</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <PrintCats menuActions={menuActions} cats={cats}/>
    </div>
}

function PrintCats({menuActions, cats}) {
    const {cards_v} = useCards();
    const {sendRequest} = useWS();

    function readAndConvertMatch(matches, data) {
        matches.push({
            ...data,
            c1: data.c1?.id,
            c2: data.c2?.id,
            c1_cacheName: data.c1?.fname + " " + data.c1?.lname,
            c2_cacheName: data.c2?.fname + " " + data.c2?.lname
        })
    }

    const run = (categorieEmpty, cats2, name = "") => {
        const pagesPromise = cats2.sort((a, b) => a.name.localeCompare(b.name)).map(cat_ => {
            return sendRequest('getFullCategory', cat_.id)
                .then((data) => {
                    const cat = {
                        id: data.id,
                        name: data.name,
                        liceName: data.liceName,
                        type: data.type,
                        trees: data.trees.sort((a, b) => a.level - b.level).map(d => from_sendTree(d, true)),
                        raw_trees: data.trees.sort((a, b) => a.level - b.level),
                        treeAreClassement: data.treeAreClassement,
                        fullClassement: data.fullClassement,
                        preset: data.preset,
                    }
                    if (name === "") {
                        name = data.preset.name;
                    }

                    const newCards = {};
                    for (const o of data.cards)
                        newCards[o.id] = o

                    let matches2 = [];
                    data.trees.flatMap(d => from_sendTree(d, false).flat()).forEach((data_) => readAndConvertMatch(matches2, data_));
                    data.matches.forEach((data_) => readAndConvertMatch(matches2, data_));

                    const activeMatches = matches2.filter(m => m.poule !== '-')
                    const groups = matches2.flatMap(d => [d.c1, d.c2]).filter((v, i, a) => v != null && a.indexOf(v) === i)
                        .map(d => {
                            let poule = activeMatches.find(m => (m.c1 === d || m.c2 === d) && m.categorie_ord !== -42)?.poule
                            if (!poule)
                                poule = '-'
                            return {id: d, poule: poule}
                        })

                    matches2 = matches2.filter(m => m.categorie === cat.id)
                        .map(m => ({...m, ...win_end(m, cards_v)}))
                    matches2.forEach(m => {
                        if (m.end && (!m.scores || m.scores.length === 0))
                            m.scores = [{n_round: 0, s1: 0, s2: 0}];
                    })

                    return {
                        type: "categorie",
                        params: ({cat, matches: matches2, groups, cards_v: Object.values({...cards_v, ...newCards}), categorieEmpty})
                    }
                })
        })

        return Promise.allSettled(pagesPromise)
            .then((results) => {
                const pages = [];
                let error = 0;

                for (const result of results) {
                    if (result.status === "fulfilled") {
                        pages.push(result.value);
                    } else {
                        console.error(result.error);
                        error++;
                    }
                }

                return [name, pages, error];
            })
    }

    menuActions.printCategoriePreset = (categorieEmpty, preset) => {
        return run(categorieEmpty, cats.filter(cat => cat.preset?.id === preset))
    }

    menuActions.printAllCategorie = (categorieEmpty, name) => {
        return run(categorieEmpty, cats, name)
    }
}

function ModalContent({state, setCatId, setConfirm, confirmRef}) {
    const id = useId()
    const [name, setName] = useState("")
    const [lice, setLice] = useState("1")
    const [poule, setPoule] = useState(true)
    const [tournoi, setTournoi] = useState(false)
    const [classement, setClassement] = useState(true)
    const [fullClassement, setFullClassement] = useState(false)
    const [size, setSize] = useState(4)
    const [loserMatch, setLoserMatch] = useState(1)
    const [preset, setPreset] = useState(-1)
    const {t} = useTranslation("cm");

    const {sendRequest} = useWS();

    useEffect(() => {
        console.log(state);
        setName(state.name || "");
        setLice(state.liceName || "1");
        setPoule(((state.type || 1) & 1) !== 0);
        setTournoi((state.type & 2) !== 0);
        setClassement(state.treeAreClassement !== undefined && state.treeAreClassement !== false);
        setFullClassement(state.fullClassement !== undefined && state.fullClassement !== false);
        setPreset(state.preset?.id || -1);

        let trees_ = []
        for (let i = 0; i < state?.raw_trees?.length; i++) {
            if (state.raw_trees.at(i).level > 0) {
                trees_.push(state.trees.at(i))
            }
        }
        if (trees_ && trees_.length >= 1) {
            const tree = trees_[0];
            setSize(tree.getMaxChildrenAtDepth(tree.death() - 1) * 2);

            if (trees_.length === 1) {
                setLoserMatch(0);
            } else if (trees_.length === 2) {
                setLoserMatch(1);
            } else {
                setLoserMatch(-1);
            }
        } else {
            setSize(4);
            setLoserMatch(1);
        }
    }, [state])

    const handleSubmit = (e) => {
        e.preventDefault();

        const regex = /^([^;]+;)*[^;]+$/;
        if (regex.test(lice.trim()) === false) {
            toast.error(t('err2'));
            return;
        }

        const nType = (poule ? 1 : 0) + (tournoi ? 2 : 0);
        if (nType === 0) {
            toast.error(t('err3'));
            return;
        }

        let trees_ = []
        for (let i = 0; i < state?.raw_trees?.length; i++) {
            if (state.raw_trees.at(i).level > 0) {
                trees_.push(state.trees.at(i))
            }
        }
        if (state?.id) {
            const applyChanges = () => {
                const newData = {
                    id: state.id,
                    name: name.trim(),
                    liceName: lice.trim(),
                    type: nType,
                    treeAreClassement: classement,
                    fullClassement: fullClassement,
                    preset: {id: preset !== -1 ? preset : null}
                }

                let nbMatch = -1;
                let oldSubTree = -1;
                const oldTrees = trees_ || [];
                if (oldTrees.length >= 1) {
                    const tree = trees_[0];
                    nbMatch = tree.getMaxChildrenAtDepth(tree.death() - 1);
                    if (trees_.length === 1)
                        oldSubTree = 0
                    else if (trees_.length === 2)
                        oldSubTree = 1
                }

                console.log(tournoi, size, nbMatch, loserMatch, oldSubTree);
                if (tournoi && (size !== nbMatch * 2 || loserMatch !== oldSubTree)) {
                    setConfirm({
                        title: t('confirm2.title'),
                        message: t('confirm2.msg'),
                        confirm: () => {
                            const trees2 = build_tree(size, loserMatch)
                            const newTrees = []

                            let i = 0;
                            for (; i < oldTrees.length && i < trees2.length; i++) {
                                newTrees.push(oldTrees[i]);
                                resize_tree(newTrees.at(i), trees2.at(i));
                            }

                            for (; i < trees2.length; i++) {
                                newTrees.push(trees2.at(i));
                            }

                            toast.promise(sendRequest('updateTrees', {
                                    categoryId: state.id,
                                    trees: newTrees
                                }), getToastMessage("toast.updateTrees", "cm")
                            ).then(__ => {
                                toast.promise(sendRequest('updateCategory', newData), getToastMessage("toast.updateCategory", "cm"))
                            })
                        }
                    })
                    confirmRef.current.click();
                } else {
                    toast.promise(sendRequest('updateCategory', newData), getToastMessage("toast.updateCategory", "cm"))
                }
            }

            if (nType !== state.type) {
                let typeStr = "";
                if ((state.type & 1) !== 0 && (nType & 1) === 0)
                    typeStr += `${t('poule').toLowerCase()} `;
                if ((state.type & 2) !== 0 && (nType & 2) === 0)
                    typeStr += `${t('tournoi').toLowerCase()} `;

                setConfirm({
                    title: t('confirm3.title'),
                    message: t('confirm3.msg', {typeStr: typeStr.trim()}),
                    confirm: () => {
                        setTimeout(() => applyChanges(), 500);
                    }
                })
                confirmRef.current.click();
            } else {
                applyChanges();
            }
        } else {
            toast.promise(sendRequest('createCategory', {
                    name: name.trim(),
                    liceName: lice.trim(),
                    type: nType,
                    treeAreClassement: classement,
                    fullClassement: fullClassement,
                    preset: {id: preset !== -1 ? preset : null}
                }), getToastMessage("toast.createCategory", "cm")
            ).then(id => {
                if (tournoi) {
                    const trees = build_tree(size, loserMatch)
                    console.log("Creating trees for new category:", trees);

                    toast.promise(sendRequest('updateTrees', {categoryId: id, trees: trees}), getToastMessage("toast.updateTrees.init", "cm")
                    ).finally(() => setCatId(id))
                } else {
                    setCatId(id);
                }
            })
        }
    }

    return <form onSubmit={handleSubmit}>
        <div className="modal-header">
            <h1 className="modal-title fs-5" id="CategorieModalLabel">{state.id === undefined ? t('ajouter') : t('modifier')} {t('uneCatégorie')}</h1>
            <button type="button" className="btn-close" data-bs-dismiss="modal"
                    aria-label="Close"></button>
        </div>
        <div className="modal-body">
            <div className="mb-3">
                <label htmlFor="nameInput1" className="form-label">{t('nom')}</label>
                <input type="text" className="form-control" id="nameInput1" placeholder={t('epéeBouclier')} name="name" value={name}
                       onChange={e => setName(e.target.value)}/>
            </div>

            <ListPresetSelect value={preset} onChange={setPreset}/>

            <div className="mb-3">
                <label htmlFor={id + "liceInput1"} className="form-label"><Trans i18nKey="nomDesZonesDeCombat" ns="cm">t <small>(séparée par des
                    ';')</small></Trans></label>
                <input type="text" className="form-control" id={id + "liceInput1"} placeholder="1;2" name="zone de combat" value={lice}
                       onChange={e => setLice(e.target.value)}/>
            </div>


            <div className="mb-3">
                <label className="form-label">{t('type')}</label>
                <div className="form-check form-switch">
                    <input className="form-check-input" type="checkbox" role="switch" id="switchCheckDefault" name="poule" checked={poule}
                           onChange={e => setPoule(e.target.checked)}/>
                    <label className="form-check-label" htmlFor="switchCheckDefault">{t('poule')}</label>
                </div>

                <div className="form-check form-switch">
                    <input className="form-check-input" type="checkbox" role="switch" id="switchCheckDefault2" name="trournoi" checked={tournoi}
                           onChange={e => setTournoi(e.target.checked)}/>
                    <label className="form-check-label" htmlFor="switchCheckDefault2">{t('tournoi')}</label>
                </div>

                <div className="form-check">
                    <input className="form-check-input" type="checkbox" value="" id="checkDefault" disabled={!tournoi} checked={classement}
                           onChange={e => setClassement(e.target.checked)}/>
                    <label className="form-check-label" htmlFor="checkDefault">
                        {t('leTournoiServiraDePhaseFinaleAuxPoules')}
                    </label>
                </div>
            </div>


            <div className="mb-3">
                <label htmlFor="sizeInput1" className="form-label">Nombre de combattants</label>
                <input type="number" className="form-control" id="sizeInput1" placeholder="4" name="size" disabled={!tournoi} value={size}
                       onChange={e => setSize(Number.parseInt(e.target.value))}/>
            </div>

            <div className="mb-3">
                <span>{t('matchPourLesPerdantsDuTournoi')}</span>
                <div className="form-check">
                    <input className="form-check-input" type="radio" name="radioDefault" id="radioDefault1" disabled={!tournoi}
                           checked={loserMatch === -1} onChange={e => {
                        if (e.target.checked) setLoserMatch(-1)
                    }}/>
                    <label className="form-check-label" htmlFor="radioDefault1">
                        {t('tousLesMatchs')}
                    </label>
                </div>
                <div className="form-check">
                    <input className="form-check-input" type="radio" name="radioDefault" id="radioDefault2" disabled={!tournoi}
                           checked={loserMatch === 1} onChange={e => {
                        if (e.target.checked) setLoserMatch(1)
                    }}/>
                    <label className="form-check-label" htmlFor="radioDefault2">
                        {t('demi-finalesEtFinales')}
                    </label>
                </div>
                <div className="form-check">
                    <input className="form-check-input" type="radio" name="radioDefault" id="radioDefault3" disabled={!tournoi}
                           checked={loserMatch === 0} onChange={e => {
                        if (e.target.checked) setLoserMatch(0)
                    }}/>
                    <label className="form-check-label" htmlFor="radioDefault3">
                        {t('finalesUniquement')}
                    </label>
                </div>
            </div>

            <div className="form-check">
                <input className="form-check-input" type="checkbox" value="" id="checkDefault2" disabled={!tournoi || !classement}
                       checked={fullClassement} onChange={e => setFullClassement(e.target.checked)}/>
                <label className="form-check-label" htmlFor="checkDefault2">
                    {t('lesCombattantsEnDehors')}
                </label>
            </div>

        </div>
        <div className="modal-footer">
            <button type="button" className="btn btn-secondary" data-bs-dismiss="modal">{t('fermer')}</button>
            <button type="submit" className="btn btn-primary" data-bs-dismiss="modal">{t('enregistrer')}</button>
            {state.id !== undefined && <button type="button" className="btn btn-danger" data-bs-dismiss="modal" onClick={() => {
                setConfirm({
                    title: t('confirm4.title'),
                    message: t('confirm4.msg', {name: state.name}),
                    confirm: () => {
                        toast.promise(sendRequest('deleteCategory', state.id), getToastMessage("toast.deleteCategory", "cm")
                        ).then(() => setCatId(null));
                    }
                })
                confirmRef.current.click();
            }}>{t('supprimer')}</button>}
        </div>
    </form>
}
