import {useNavigate, useParams} from "react-router-dom";
import {LoadingProvider, useLoadingSwitcher} from "../../hooks/useLoading.jsx";
import {useFetch} from "../../hooks/useFetch.js";
import {AxiosError} from "../../components/AxiosError.jsx";
import {ThreeDots} from "react-loader-spinner";
import React, {useEffect, useId, useReducer, useRef, useState} from "react";
import {apiAxios, applyOverCategory, CatList, getCatFromName, getCatName, getToastMessage} from "../../utils/Tools.js";
import {toast} from "react-toastify";
import {SimpleReducer} from "../../utils/SimpleReducer.jsx";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faAdd, faGavel, faLock, faTrashCan} from "@fortawesome/free-solid-svg-icons";
import "./CompetitionRegisterAdmin.css"
import * as XLSX from "xlsx-js-style";
import {useCountries} from "../../hooks/useCountries.jsx";
import {Trans, useTranslation} from "react-i18next";
import {Checkbox} from "../../components/MemberCustomFiels.jsx";
import {FileImport} from "../../components/FileImport.jsx";

export function CompetitionRegisterAdmin({source}) {
    const {id} = useParams()
    const navigate = useNavigate()
    const [state, dispatch] = useReducer(SimpleReducer, [])
    const [clubFilter, setClubFilter] = useState("")
    const [catAgeFilter, setCatAgeFilter] = useState("")
    const [catFilter, setCatFilter] = useState(-1)
    const [filterNotWeight, setFilterNotWeight] = useState(false)
    const [modalState, setModalState] = useState({})
    const {t} = useTranslation();

    const setLoading = useLoadingSwitcher()
    const {data, error} = useFetch(`/competition/${id}/register/${source}`, setLoading, 1)
    const {data: data2, error: error2} = useFetch(`/competition/${id}/categories`, setLoading, 1)
    const {data: data3} = useFetch(`/competition/${id}?light=true`, setLoading, 1)

    const sortName = (a, b) => {
        if (a.data.fname === b.data.fname) return a.data.lname.localeCompare(b.data.lname);
        return a.data.fname.localeCompare(b.data.fname);
    }

    useEffect(() => {
        if (!data) return;
        data.forEach((d) => {
            dispatch({type: 'UPDATE_OR_ADD', payload: {id: d.id, data: d}})
        })
        dispatch({type: 'SORT', payload: sortName})
    }, [data, clubFilter, catFilter]);

    const sendRegister = (new_state) => {
        return toast.promise(apiAxios.post(`/competition/${id}/register/${source}`, new_state), getToastMessage("comp.toast.register.add")
        ).then((response) => {
            if (response.data.error) {
                return null;
            }
            dispatch({type: 'UPDATE_OR_ADD', payload: {id: response.data.id, data: response.data}})
            dispatch({type: 'SORT', payload: sortName})
            return response.data
        })
    }
    const sendRegisters = (new_state) => {
        toast.promise(apiAxios.post(`/competition/${id}/registers/${source}`, new_state), getToastMessage("comp.toast.registers.addMultiple")
        ).then((response) => {
            if (response.data.error)
                return;

            let i = 0;
            response.data.forEach((d) => {
                if (d.licence === -42) {
                    toast.warn(t('erreurPourLinscription') + " :" + d.lname, {autoClose: false});
                } else {
                    dispatch({type: 'UPDATE_OR_ADD', payload: {id: d.id, data: d}})
                    i++;
                }
            })
            if (i > 0)
                toast.success(t('comp.toast.register.addMultiple.success', {count: i}))
            dispatch({type: 'SORT', payload: sortName})
        })
    }

    return <div>
        <h2>{t('comp.combattantsInscrits')}</h2>
        <button type="button" className="btn btn-link"
                onClick={() => source === "admin" ? navigate("/competition/" + id) : navigate("/competition/" + id + "/view")}>
            {t('back')}
        </button>

        <div className="row">
            <div className="col-lg-9">
                {data ? <div className="">
                    <MakeCentralPanel
                        data={state.filter(s => (clubFilter.length === 0 || s.data.club?.name === clubFilter)
                            && (catAgeFilter.length === 0 || s.data.categorie === catAgeFilter)
                            && (catFilter === -1 || s.data.categoriesInscrites.includes(catFilter))
                            && (!filterNotWeight || (data3?.requiredWeight.includes(s.data.categorie) && (
                                (source === "admin" && (s.data.weightReal === "" || s.data.weightReal === null)) ||
                                (source !== "admin" && (s.data.weight === "" || s.data.weight === null))
                            )))
                        )}
                        data2={data2} data3={data3} dispatch={dispatch} id={id} setModalState={setModalState} source={source}/>
                </div> : error ? <AxiosError error={error}/> : <Def/>}
            </div>
            <div className="col-lg-3">
                <div className="mb-1">
                    <button type="button" className="btn btn-primary" data-bs-toggle="modal" data-bs-target="#registerModal"
                            onClick={() => setModalState({id: 0})}>{t('comp.ajouterUnCombattant')}
                    </button>
                </div>
                {source === "admin" && <div className="mb-4">
                    <button type="button" className="btn btn-primary" data-bs-toggle="modal" data-bs-target="#registerModal"
                            onClick={() => setModalState({id: -793548328091516928})}>{t('comp.ajouterUnInvité')}
                    </button>
                </div>}
                <QuickAdd sendRegister={sendRegister} source={source} data2={data2} error2={error2}/>
                <div className="card mb-4">
                    <div className="card-header">{t('filtre')}</div>
                    <div className="card-body">
                        <FiltreBar data={data} data2={data2} clubFilter={clubFilter} setClubFilter={setClubFilter} catFilter={catFilter}
                                   setCatFilter={setCatFilter} catAgeFilter={catAgeFilter} setCatAgeFilter={setCatAgeFilter}
                                   filterNotWeight={filterNotWeight} setFilterNotWeight={setFilterNotWeight} source={source}/>
                    </div>
                </div>
                {source === "admin" && <div className="mb-2"><FileOutput data={data} data2={data2}/></div>}
                {source === "admin" && <div className="mb-2"><FileImportComb data2={data2} sendRegisters={sendRegisters}/></div>}
                {source === "admin" && <div className="mb-2"><FileImportGuest data2={data2} sendRegisters={sendRegisters}/></div>}
            </div>
        </div>

        <Modal_ data2={data2} error2={error2} data3={data3} sendRegister={sendRegister} modalState={modalState} setModalState={setModalState}
                source={source}/>
    </div>
}

function QuickAdd({sendRegister, source, data2, error2}) {
    const {t} = useTranslation();
    const [categories, setCategories] = useState([])

    const handleAdd = (licence) => {
        sendRegister({
            licence: licence,
            fname: "",
            lname: "",
            weight: "",
            overCategory: 0,
            lockEdit: false,
            id: null,
            quick: true,
            categoriesInscrites: categories
        })
    }

    const setCategories_ = (e, catId) => {
        if (e.target.checked) {
            if (!categories.includes(catId)) {
                setCategories([...categories, catId])
            }
        } else {
            setCategories(categories.filter(c => c !== catId))
        }
    }

    return <div className="card mb-4">
        <div className="card-header">{t('comp.ajoutRapide')}</div>
        <div className="card-body">
            <div className="d-flex flex-wrap">
                <label htmlFor="inputState2" className="form-label  align-self-center" style={{margin: "0 0.5em 0 0"}}>
                    {t('catégorieàAjouter')}<br/> <small>({t('siDisponiblePourLaCatégorieDages')})</small>
                </label>
                <CategoriesList error2={error2} availableCats={data2?.sort((a, b) => a.name.localeCompare(b.name))} categories={categories}
                                setCategories={setCategories_}/>
            </div>

            <div className="row">
                <span>{t('comp.noDeLicence')}</span>
            </div>
            <div className="input-group">
                <input type="text" className="form-control" placeholder="12345" id="quickAddLicence"
                       onKeyDown={e => {
                           if (e.key === "Enter") {
                               const licence = e.target.value.trim()
                               if (licence.length === 0) return;
                               e.target.value = ""
                               handleAdd(licence)
                           }
                       }}/>
                <button className="btn btn-primary" type="button" id="quickAddBtn"
                        onClick={_ => {
                            const licence = document.getElementById("quickAddLicence").value.trim()
                            if (licence.length === 0) return;

                            document.getElementById("quickAddLicence").value = ""
                            handleAdd(licence)
                        }}><FontAwesomeIcon icon={faAdd} className="no-modal"/>
                </button>

                {source === "club" && <LoadingProvider>
                    <SearchMember sendRegister={sendRegister} categories={categories}/>
                </LoadingProvider>}
            </div>
        </div>
    </div>
}

function SearchMember({sendRegister, categories}) {
    const setLoading = useLoadingSwitcher()
    const {data, error} = useFetch(`/club/members`, setLoading, 1)
    const [suggestions, setSuggestions] = useState([])
    const {t} = useTranslation();

    const handleAdd = (name) => {
        const member = data.find(m => `${m.fname} ${m.lname}`.trim() === name);
        if (!member) {
            toast.error(t('comp.combattantNonTrouvé'));
            return;
        }

        sendRegister({
            licence: member.licence,
            fname: member.fname,
            lname: member.lname,
            weight: "",
            overCategory: 0,
            lockEdit: false,
            id: null,
            quick: true,
            categoriesInscrites: categories
        })
    }

    useEffect(() => {
        if (!data) return;

        const names = data.map(member => `${member.fname} ${member.lname}`.trim());
        names.sort((a, b) => a.localeCompare(b));
        setSuggestions(names);
    }, [data]);

    return <>
        {data ? <div className="row mb-3" style={{marginTop: "0.5em"}}>
            <span>{t('prénomEtNom')}</span>
            <AutoCompleteInput suggestions={suggestions} handleAdd={handleAdd}/>
        </div> : error ? <AxiosError error={error}/> : <Def/>}
    </>
}

const AutoCompleteInput = ({suggestions = [], handleAdd}) => {
    const [inputValue, setInputValue] = useState('');
    const [filteredSuggestions, setFilteredSuggestions] = useState([]);
    const [showSuggestions, setShowSuggestions] = useState(false);
    const [activeSuggestion, setActiveSuggestion] = useState(0);
    const wrapperRef = useRef(null);
    const {t} = useTranslation();

    // Filtre les suggestions
    useEffect(() => {
        if (inputValue.trim() === '') {
            setFilteredSuggestions([]);
            setShowSuggestions(false);
        } else {
            const filtered = suggestions.filter(suggestion => suggestion.toLowerCase().includes(inputValue.toLowerCase()));
            setFilteredSuggestions(filtered);
            setShowSuggestions(true);
            setActiveSuggestion(0); // Réinitialise la sélection active
        }
    }, [inputValue, suggestions]);

    // Ferme les suggestions si clic à l'extérieur
    useEffect(() => {
        const handleClickOutside = (event) => {
            if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
                setShowSuggestions(false);
            }
        };
        document.addEventListener('mousedown', handleClickOutside);
        return () => document.removeEventListener('mousedown', handleClickOutside);
    }, []);

    // Gestion du clic sur une suggestion
    const handleSuggestionClick = (suggestion) => {
        setInputValue(suggestion);
        setShowSuggestions(false); // Ferme automatiquement après sélection
    };

    // Navigation clavier
    const handleKeyDown = (e) => {
        // Touches directionnelles
        if (e.key === 'ArrowDown') {
            e.preventDefault();
            setActiveSuggestion(prev => prev < filteredSuggestions.length - 1 ? prev + 1 : prev);
        } else if (e.key === 'ArrowUp') {
            e.preventDefault();
            setActiveSuggestion(prev => (prev > 0 ? prev - 1 : 0));
        }
        // Validation avec Entrée
        else if (e.key === 'Enter' && filteredSuggestions.length > 0) {
            e.preventDefault();
            if (inputValue === filteredSuggestions[activeSuggestion]) {
                handleAdd(inputValue);
                setInputValue('');
            } else {
                setInputValue(filteredSuggestions[activeSuggestion]);
            }
            setShowSuggestions(false);
        }
        // Fermeture avec Échap
        else if (e.key === 'Escape') {
            setShowSuggestions(false);
        }
    };

    return (<div className="autocomplete-wrapper" ref={wrapperRef}>
        <div className="input-group">
            <input
                type="text"
                className="form-control"
                value={inputValue}
                onChange={(e) => setInputValue(e.target.value)}
                onKeyDown={handleKeyDown}
                onFocus={() => inputValue && setShowSuggestions(true)}
                placeholder={t('rechercher...')}
                aria-autocomplete="list"
                aria-expanded={showSuggestions}
                aria-controls="suggestions-list"
            />

            <button className="btn btn-primary" type="button" id="quickAddBtn"
                    onClick={_ => {
                        handleAdd(inputValue);
                        setInputValue(''); // Réinitialise le champ après l'ajout
                    }}>
                <FontAwesomeIcon icon={faAdd} className="no-modal"/>
            </button>
        </div>
        {showSuggestions && filteredSuggestions.length > 0 && (<ul
            id="suggestions-list"
            className="suggestions-list list-group"
            role="listbox"
        >
            {filteredSuggestions.map((suggestion, index) => (<li
                key={index}
                className={`list-group-item list-group-item-action ${index === activeSuggestion ? 'active' : ''}`}
                onClick={() => handleSuggestionClick(suggestion)}
                role="option"
                aria-selected={index === activeSuggestion}
            >
                {suggestion}
            </li>))}
        </ul>)}
    </div>);
};

function CategoriesList({error2, availableCats, fistCatInput, categories, setCategories}) {
    const {t} = useTranslation();
    const id = useId();

    return <>
        {error2 ? <AxiosError error={error2}/> : <>
            {availableCats && availableCats.length === 0 && <div>{t('aucuneCatégorieDisponible')}</div>}
            {availableCats && availableCats.map((cat, index) =>
                <div key={cat.id} className="input-group"
                     style={{display: "contents"}}>
                    <div className="input-group-text">
                        <input ref={index === 0 ? fistCatInput : undefined} className="form-check-input mt-0" type="checkbox"
                               id={id + "categoriesInput" + index} checked={categories.includes(cat.id)} aria-label={cat.name}
                               onChange={e => setCategories(e, cat.id)}/>
                        <label style={{marginLeft: "0.5em"}} htmlFor={id + "categoriesInput" + index}>{cat.name}</label>
                    </div>
                </div>)}
        </>}
    </>
}

function Modal_({data2, data3, error2, sendRegister, modalState, setModalState, source}) {
    const country = useCountries('fr')
    const {t} = useTranslation();
    const closeBtn = useRef(null);
    const licenceInput = useRef(null);
    const nameInput = useRef(null);
    const fistCatInput = useRef(null);
    const submitBtn = useRef(null);

    const [licence, setLicence] = useState("")
    const [fname, setFname] = useState("")
    const [lname, setLname] = useState("")
    const [weight, setWeight] = useState("")
    const [weightReal, setWeightReal] = useState("")
    const [cat, setCat] = useState(0)
    const [gcat, setGCat] = useState("")
    const [club, setClub] = useState("")
    const [country_, setCountry_] = useState("FR")
    const [genre, setGenre] = useState("NA")
    const [editMode, setEditMode] = useState(false)
    const [lockEdit, setLockEdit] = useState(false)
    const [categories, setCategories] = useState([])

    useEffect(() => {
        setLicence(modalState?.licence ? modalState.licence : "")
        setFname(modalState?.fname ? modalState.fname : "")
        setLname(modalState?.lname ? modalState.lname : "")
        setWeight(modalState?.weight ? modalState.weight : "")
        setWeightReal(modalState?.weightReal ? modalState.weightReal : "")
        setCat(modalState?.overCategory ? modalState.overCategory : 0)
        setEditMode(modalState?.licence || (modalState.fname && modalState.lname))
        setLockEdit(modalState?.lockEdit === undefined ? false : modalState.lockEdit)
        setClub(modalState?.club ? modalState.club.name : "")
        setGCat(modalState?.categorie ? modalState.categorie : "")
        setCountry_(modalState?.country ? modalState.country : "FR")
        setGenre(modalState?.genre ? modalState.genre : "NA")
        setCategories(modalState?.categoriesInscrites ? modalState.categoriesInscrites : [])

        setTimeout(() => {
            if (modalState?.id === 0) {
                licenceInput.current?.focus()
            } else if (modalState?.id < 0) {
                nameInput.current?.focus()
            }
        }, 450)
    }, [modalState]);

    const setCategories_ = (e, catId) => {
        if (e.target.checked) {
            if (!categories.includes(catId)) {
                setCategories([...categories, catId])
            }
        } else {
            setCategories(categories.filter(c => c !== catId))
        }
    }

    const handleSubmit = (e) => {
        e.preventDefault()
        const new_state = {
            licence: Number.isInteger(licence) ? licence : licence.trim(),
            fname: fname.trim(),
            lname: lname.trim(),
            weight: weight,
            weightReal: weightReal,
            overCategory: cat,
            lockEdit: lockEdit,
            categoriesInscrites: categories,
            id: modalState.id !== 0 ? modalState.id : null
        }
        if (modalState.id < 0) {
            new_state.licence = -1
            new_state.categorie = gcat
            new_state.club = club
            new_state.country = country_
            new_state.genre = genre
        }
        sendRegister(new_state)
            .then(data => {
                if (!data) return;
                setModalState(data)
                if (editMode || data.id < 0) {
                    closeBtn.current.click()
                } else {
                    setTimeout(() => {
                        if (fistCatInput.current) {
                            fistCatInput.current.focus()
                        } else {
                            submitBtn.current.focus()
                        }
                    }, 100)
                }
            })
    }

    const currenCat = gcat !== "" ? applyOverCategory(gcat, cat) : "";
    const availableCats = data2 ? (currenCat !== "" ? data2.filter(c => c.categories.some(c2 => c2.categorie === currenCat)) : data2).sort((a, b) => a.name.localeCompare(b.name)) : []
    if (availableCats.length === 0) {
        if (fistCatInput.current) {
            fistCatInput.current = null
        }
    }

    return <div className="modal fade" id="registerModal" tabIndex="-1" aria-labelledby="registerLabel" aria-hidden="true">
        <div className="modal-dialog">
            <div className="modal-content">
                <div className="modal-header">
                    <h1 className="modal-title fs-5"
                        id="registerLabel">{editMode ? t('modification') : t('ajout')} {t('dun')} {modalState.id >= 0 ? t('combattant') : t('invité')}</h1>
                    <button ref={closeBtn} type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div className="modal-body">
                    {modalState.id < 0 &&
                        <div className="mb-2">{t('comp.modal.text1')}</div>}
                    <div className="card" style={{marginBottom: "1em"}}>
                        <div className="card-header">{modalState.id >= 0 ? t('comp.modal.recherche') : t('comp.modal.information')}</div>
                        <div className="card-body">
                            <div className="row" hidden={modalState.id < 0}>
                                <div className="col">
                                    <input ref={licenceInput} type="number" min={0} step={1} className="form-control"
                                           placeholder={t("comp.noDeLicence")} name="licence" value={licence}
                                           onChange={e => setLicence(e.target.value)} disabled={editMode}
                                           onKeyUp={e => e.key === "Enter" ? handleSubmit(e) : undefined}/>
                                </div>
                            </div>
                            <h5 style={{textAlign: "center", marginTop: "0.25em"}} hidden={modalState.id < 0}>{t('ou')}</h5>
                            <div className="row">
                                <div className="col">
                                    <input ref={nameInput} type="text" className="form-control" placeholder={t('prenom')} name="fname"
                                           disabled={editMode && modalState.id >= 0}
                                           value={fname} onChange={e => setFname(e.target.value)}/>
                                </div>
                                <div className="col">
                                    <input type="text" className="form-control" placeholder={t('nom')} name="lname"
                                           disabled={editMode && modalState.id >= 0} value={lname} onChange={e => setLname(e.target.value)}
                                           onKeyUp={e => e.key === "Enter" && modalState.id >= 0 ? handleSubmit(e) : undefined}/>
                                </div>
                            </div>
                        </div>
                    </div>

                    {(editMode || modalState.id < 0) && <>
                        <div className="input-group mb-3" hidden={modalState.id >= 0}>
                            <span className="input-group-text" id="categorie">{t("club", {count: 1})}</span>
                            <input type="text" className="form-control" placeholder={t("club", {count: 1})} name="club"
                                   value={club} onChange={e => setClub(e.target.value)}/>
                        </div>

                        <div className="input-group mb-3" hidden={modalState.id >= 0}>
                            <span className="input-group-text" id="categorie">{t('catégorie')}</span>
                            <select id="inputState2" className="form-select" value={gcat}
                                    onChange={(e) => setGCat(e.target.value)}>
                                <option>{t('--SélectionnerCatégorie--')}</option>
                                {CatList.map((cat, index) => {
                                    return (<option key={index} value={cat}>{getCatName(cat)}</option>)
                                })}
                            </select>
                        </div>

                        <div className="input-group mb-3" hidden={modalState.id >= 0}>
                            <span className="input-group-text" id="pays">{t('pays')}</span>
                            <select id="inputState0" className="form-select" value={country_} onChange={(e) => setCountry_(e.target.value)}>
                                {country && Object.keys(country).sort((a, b) => {
                                    if (a < b) return -1
                                    if (a > b) return 1
                                    return 0
                                }).map((key, _) => {
                                    return (<option key={key} value={key}>{country[key]}</option>)
                                })}
                            </select>
                        </div>

                        <div className="input-group mb-3" hidden={modalState.id >= 0}>
                            <span className="input-group-text" id="genre">{t('genre')}</span>
                            <select className="form-select" aria-label={t('categorie')} name="genre" value={genre}
                                    onChange={e => setGenre(e.target.value)}>
                                <option value={"NA"}>NA</option>
                                <option value={"H"}>{t('h')}</option>
                                <option value={"F"}>{t('f')}</option>
                            </select>
                        </div>

                        <div className="input-group mb-3">
                            <span className="input-group-text" id="weight">{t('comp.modal.poids')}</span>
                            {source === "admin" && <span className="input-group-text" id="weightReal">{t('comp.modal.annoncé')}</span>}
                            <input type="number" min={1} step={0.1} className="form-control" placeholder="--" aria-label="weight"
                                   name="weight" aria-describedby="weight" disabled={!(data3.requiredWeight.includes(currenCat))} value={weight}
                                   onChange={e => setWeight(e.target.value)}/>
                            {source === "admin" && <><span className="input-group-text" id="weightReal">{t('comp.modal.pesé')}</span>
                                <input type="number" min={1} step={0.1} className="form-control" placeholder="--" aria-label="weightReal"
                                       name="weightReal" aria-describedby="weightReal" value={weightReal}
                                       onChange={e => setWeightReal(e.target.value)}/></>}
                        </div>

                        <div className="input-group mb-3" hidden={modalState.id < 0}>
                            <span className="input-group-text" id="surclassement">{t('comp.modal.surclassement')}</span>
                            <select className="form-select" aria-label={t('comp.modal.surclassement')} name="surclassement" value={cat}
                                    onChange={e => setCat(Number(e.target.value))}>
                                <option value={0}>{t('aucun')}</option>
                                <option value={1}>{t('1Catégorie')}</option>
                                <option value={2}>{t('2Catégorie')}</option>
                            </select>
                        </div>

                        {editMode && source === "admin" && <div className="form-check form-switch form-check-reverse" hidden={modalState.id < 0}>
                            <input className="form-check-input" type="checkbox" id="switchCheckReverse" checked={lockEdit}
                                   onChange={e => setLockEdit(e.target.checked)}/>
                            <label className="form-check-label" htmlFor="switchCheckReverse">{t('comp.modal.text2')}</label>
                        </div>}

                        <div className="d-flex flex-wrap">
                            <label htmlFor="inputState2" className="form-label  align-self-center" style={{margin: "0 0.5em 0 0"}}>
                                {t('catégorie')} :
                            </label>
                            <CategoriesList error2={error2} availableCats={availableCats} fistCatInput={fistCatInput} categories={categories}
                                            setCategories={setCategories_}/>
                        </div>
                    </>}
                </div>
                <div className="modal-footer">
                    <button type="button" className="btn btn-secondary" data-bs-dismiss="modal" id="closeModal">{t('button.annuler')}</button>
                    <button ref={submitBtn} type="button" className="btn btn-primary"
                            onClick={handleSubmit}>{editMode ? t('button.modifier') : t('button.ajouter')}</button>
                </div>
            </div>
        </div>
    </div>
}

let allClub = []

function FiltreBar({
                       data,
                       data2,
                       clubFilter,
                       setClubFilter,
                       catFilter,
                       setCatFilter,
                       catAgeFilter,
                       setCatAgeFilter,
                       filterNotWeight,
                       setFilterNotWeight,
                       source
                   }) {
    const {t} = useTranslation();
    useEffect(() => {
        if (!data) return;
        allClub.push(...data.map((e) => e.club?.name))
        allClub = allClub.filter((value, index, self) => self.indexOf(value) === index).filter(value => value != null).sort()
    }, [data]);

    return <div>
        <div className="mb-3">
            <Checkbox value={filterNotWeight} onChange={setFilterNotWeight} name="checkbox2" label={t('afficherLesCombattantsNonPesés')}/>
        </div>

        {source === "admin" && <div className="mb-3">
            <select className="form-select" value={clubFilter} onChange={event => setClubFilter(event.target.value)}>
                <option value="">{t('---ToutLesClubs---')}</option>
                {allClub && allClub.map((value, index) => {
                    return <option key={index} value={value}>{value}</option>
                })}
            </select>
        </div>}
        <div className="mb-3">
            <select className="form-select" value={catAgeFilter} onChange={event => setCatAgeFilter(event.target.value)}>
                <option value="">{t('---TousLesAges---')}</option>
                {CatList && CatList.map((value, index) => {
                    return <option key={index} value={value}>{getCatName(value)}</option>
                })}
            </select>
        </div>
        <select className="form-select" value={catFilter} onChange={event => setCatFilter(Number(event.target.value))}>
            <option value={-1}>{t('---TouteLesCatégories---')}</option>
            {data2 && data2.map((cat) => {
                return <option key={cat.id} value={cat.id}>{cat.name}</option>
            })}
        </select>
    </div>
}

function MakeCentralPanel({data, data2, data3, dispatch, id, setModalState, source}) {
    const registerType = data3?.registerMode || "FREE";
    const {t} = useTranslation();

    return <>
        {(registerType === "FREE" || registerType === "CLUB_ADMIN") && source === "admin" &&
            <span><Trans i18nKey="comp.tips"> petite <FontAwesomeIcon icon={faGavel}/> à</Trans>
        </span>}
        <div className="mb-4">
            <div className="list-group">
                {data.map((req, index) => (<div key={index} className="list-group-item" style={{padding: "0"}}>
                    <div className="row" style={{padding: "0", margin: "0"}}>
                        <div style={{padding: ".5rem 1rem"}}
                             className={"col d-flex justify-content-between align-items-start list-group-item-" + ((req.data.lockEdit && source !== "admin") ? "secondary " : "action")}
                             data-bs-toggle={(req.data.lockEdit && source !== "admin") ? "" : "modal"} data-bs-target="#registerModal"
                             onClick={_ => setModalState({...req.data, id: req.id})}>
                            <div className="row">
                                <span className="col-auto">{req.data.licence ? String(req.data.licence).padStart(5, '0') : "-------"}</span>
                                <div className="ms-2 col-auto">
                                    <div><strong>{req.data.fname} {req.data.lname}</strong> <small>{req.data.lockEdit &&
                                        <FontAwesomeIcon icon={faLock} style={{color: "#e40101",}}/>}{req.data.genre}</small></div>
                                    <small>{req.data.club?.name || t("club", {count: 0})}</small>
                                </div>
                            </div>
                            <div className="row">
                                <div className="col-auto" style={{textAlign: "right"}}>
                                    <small>{t("comp.surclassement", {
                                        count: req.data.overCategory,
                                        cat: getCatName(req.data.categorie)
                                    })} {source !== "admin" && data3?.requiredWeight.includes(applyOverCategory(req.data.categorie, req.data.weight)) && <>
                                        | {req.data.weight ? req.data.weight : "---"} kg
                                    </>}
                                        {source === "admin" && (data3?.requiredWeight.includes(applyOverCategory(req.data.categorie, req.data.overCategory)) || req.data.weightReal) && <>
                                            | {req.data.weightReal ? <span style={{color: "#3cbc02"}}>{req.data.weightReal} kg</span> :
                                            (req.data.weight ? <span style={{color: "#e40101"}}>{req.data.weight} kg</span> : "--- kg")}
                                        </>}</small>
                                    <br/>
                                    <small>
                                        {req.data.categoriesInscrites.map(catId => data2?.find(c => c.id === catId)).filter(o => o !== undefined)
                                            .sort((a, b) => a.name.localeCompare(b.name)).map(cat =>
                                                <span key={cat.id} className="badge text-bg-secondary"
                                                      style={{margin: "0 0.125em"}}>{cat.name}</span>)}
                                    </small>
                                </div>
                            </div>
                        </div>
                        <div className="col-auto" style={{padding: "0 0.5rem 0 0", alignContent: "center"}}>
                            {(registerType === "FREE" || registerType === "CLUB_ADMIN") && source === "admin" &&
                                <button className="btn btn btn-danger no-modal" type="button" disabled={req.data.lockEdit && source !== "admin"}
                                        style={{margin: "0 0.25rem 0 0"}}
                                        onClick={e => {
                                            e.preventDefault()

                                            if (req.data.lockEdit && source !== "admin") return;
                                            if (!window.confirm(t('comp.warn1')))
                                                return;

                                            toast.promise(
                                                apiAxios.delete(`/competition/${id}/register/${req.data.id}/${source}?ban=true`), getToastMessage("comp.toast.register.ban")
                                            ).finally(() => {
                                                dispatch({type: 'REMOVE', payload: req.id})
                                            })
                                        }}>
                                    <FontAwesomeIcon icon={faGavel} className="no-modal"/>
                                </button>}
                            <button className="btn btn-danger no-modal" type="button" disabled={req.data.lockEdit && source !== "admin"}
                                    onClick={e => {
                                        e.preventDefault()

                                        if (req.data.lockEdit && source !== "admin") return;
                                        if (registerType === "HELLOASSO") {
                                            if (!window.confirm(t('comp.warn2')))
                                                return;
                                        } else {
                                            if (!window.confirm(t('comp.warn3')))
                                                return;
                                        }

                                        toast.promise(
                                            apiAxios.delete(`/competition/${id}/register/${req.data.id}/${source}?ban=false`), getToastMessage("comp.toast.register.del")
                                        ).finally(() => {
                                            dispatch({type: 'REMOVE', payload: req.id})
                                        })
                                    }}>
                                <FontAwesomeIcon icon={faTrashCan} className="no-modal"/>
                            </button>
                        </div>
                    </div>
                </div>))}
            </div>
        </div>
    </>
}

function FileOutput({data, data2}) {
    const {t} = useTranslation();

    const handleFileDownload = () => {
        const catColumns = {}
        for (const cat of data2) {
            catColumns[cat.id] = ""
        }

        const columnOrder = [
            "licence", "pays", "nom", "prenom", "genre", "weight",
            "categorie", "overCategory", "categorie2", "club",
            ...Object.keys(catColumns)
        ];

        const dataOut = []
        for (const e of data) {
            const tmp = {
                licence: e.id <= 0 ? -1 : e.licence,
                pays: e.country,
                nom: e.lname,
                prenom: e.fname,
                genre: e.genre,
                weight: e.weightReal ? e.weightReal : e.weight,
                categorie: getCatName(e.categorie),
                overCategory: e.overCategory,
                categorie2: getCatName(applyOverCategory(e.categorie, e.overCategory)),
                club: e.club ? e.club.name : '',
                ...catColumns
            }
            for (const c of e.categoriesInscrites) {
                tmp[c] = "X"
            }
            dataOut.push(tmp)
        }
        dataOut.sort((a, b) => a.prenom.localeCompare(b.prenom) || a.nom.localeCompare(b.nom));

        const secondHeaders = [
            "Licence", "Pays", "Nom", "Prénom", "Genre", "Poids",
            "Catégorie normalizer", "Surclassement", "Catégorie d'inscription", "Club",
            ...Object.keys(catColumns).map(id => data2.find(p => p.id === Number(id))?.name)
        ];
        const headers = [
            "", "", "", "", "", "", "", "", "", "", "Catégories",
            ...Object.keys(catColumns).map(() => "")
        ];

        const orderedData = dataOut.map(row => columnOrder.map(col => row[col]));

        const wb = XLSX.utils.book_new();
        const ws = XLSX.utils.json_to_sheet([], {skipHeader: true});

        XLSX.utils.sheet_add_aoa(ws, [headers, secondHeaders, ...orderedData], {origin: "A1"});

        // Fusionner les cellules pour le titre "Catégories"
        const mergeStart = XLSX.utils.encode_cell({r: 0, c: 10}); // Ligne 1, colonne K (index 10)
        const mergeEnd = XLSX.utils.encode_cell({r: 0, c: 10 + Object.keys(catColumns).length - 1});
        ws["!merges"] = [{s: mergeStart, e: mergeEnd}];

        // 10. Appliquer une rotation de 45° aux en-têtes
        const headerRow = ws["!rows"] || (ws["!rows"] = {});
        headerRow[1] = {hpt: 70}; // Hauteur de la première ligne
        for (let i = 0; i < headers.length; i++) {
            const cellRef = XLSX.utils.encode_cell({r: 1, c: i});
            if (!ws[cellRef]) ws[cellRef] = {};
            ws[cellRef].s = {
                alignment: {textRotation: 45, vertical: "bottom", wrapText: true}
            };
        }

        ws["!cols"] = [{wch: 5}, {wch: 4}, {wch: 16}, {wch: 16}, {wch: 4}, {wch: 4}, {wch: 10}, {wch: 4}, {wch: 10}, {wch: 60},
            ...Object.keys(catColumns).map(() => ({wch: 2}))]

        XLSX.utils.book_append_sheet(wb, ws, "Feuille 1");
        XLSX.writeFile(wb, "output.xlsx");
    };

    return (
        <div>
            <button className="btn btn-primary" onClick={handleFileDownload}>{t('comp.exporterLesInscription')}</button>
        </div>
    );
}

function FileImportGuest({data2, sendRegisters}) {
    const {t} = useTranslation();

    const expectedFields = [
        {key: 'nom', label: t('nom'), mandatory: true, type: 'String'},
        {key: 'prenom', label: t('prenom'), mandatory: true, type: 'String'},
        {key: 'pays', label: t('pays'), mandatory: false, type: 'String'},
        {key: 'genre', label: t('genre'), mandatory: false, type: 'String'},
        {key: 'weight', label: t('poids'), mandatory: false, type: 'Integer'},
        {key: 'categorie', label: t('catégorie'), mandatory: true, type: 'String'},
        {key: 'club', label: t('club', {count: 1}), mandatory: false, type: 'String'},
    ];

    if (data2)
        data2.forEach(row => {
            expectedFields.push({key: "__" + row.id, label: row.name, mandatory: false, type: 'Boolean'})
        })


    const onDataMapped = (mappedData) => {
        const out = []
        mappedData.forEach(row => {
            if (!row.nom || !row.prenom || !row.categorie) {
                toast.warn(t('ligneIgnorée1'))
                return;
            }

            const categoriesInscrites = []
            data2.forEach(cat => {
                if (row["__" + cat.id]) {
                    categoriesInscrites.push(cat.id)
                }
                delete row["__" + cat.id]
            })
            out.push({
                id: 0,
                licence: -1,
                fname: row.prenom.trim(),
                lname: row.nom.trim(),
                country: row.pays ? row.pays.trim() : "FR",
                genre: row.genre ? row.genre.trim() : "NA",
                categorie: getCatFromName(row.categorie.trim()),
                club: row.club ? row.club.trim() : "",
                weight: row.weight,
                overCategory: 0,
                lockEdit: false,
                categoriesInscrites: categoriesInscrites
            })
        })

        sendRegisters(out)
    }

    return <FileImport onDataMapped={onDataMapped} expectedFields={expectedFields} textButton={t('importerDesInvités')}/>
}

function FileImportComb({data2, sendRegisters}) {
    const {t} = useTranslation();

    const expectedFields = [
        {key: 'licence', label: t('licence'), mandatory: true, type: 'Integer'},
        {key: 'nom', label: t('nom'), mandatory: true, type: 'String'},
        {key: 'prenom', label: t('prenom'), mandatory: true, type: 'String'},
        {key: 'weight', label: t('poids'), mandatory: false, type: 'Integer'},
        {key: 'overCategory', label: t('comp.modal.surclassement'), mandatory: false, type: 'Integer'},
    ];

    if (data2)
        data2.forEach(row => {
            expectedFields.push({key: "__" + row.id, label: row.name, mandatory: false, type: 'Boolean'})
        })

    const onDataMapped = (mappedData) => {
        const out = []
        mappedData.forEach(row => {
            if (row.licence && row.licence <= 0)
                return;
            if (!(row.licence || (row.nom && row.prenom))) {
                toast.warn(t('ligneIgnorée2'))
                return;
            }

            const categoriesInscrites = []
            data2.forEach(cat => {
                if (row["__" + cat.id]) {
                    categoriesInscrites.push(cat.id)
                }
                delete row["__" + cat.id]
            })
            out.push({
                id: 0,
                licence: row.licence,
                fname: row.prenom.trim(),
                lname: row.nom.trim(),
                weight: row.weight,
                overCategory: row.overCategory,
                lockEdit: false,
                categoriesInscrites: categoriesInscrites
            })
        })

        sendRegisters(out)
    }

    return <FileImport onDataMapped={onDataMapped} expectedFields={expectedFields} textButton={t('importerDesCombattants')}/>
}

function Def() {
    return <div className="list-group">
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
        <li className="list-group-item"><ThreeDots/></li>
    </div>
}
