import {useCountries} from "../../../hooks/useCountries.jsx";
import React, {useEffect, useReducer, useRef, useState} from "react";
import {CatList, getCatName, getToastMessage} from "../../../utils/Tools.js";
import {CombName} from "../../../hooks/useComb.jsx";
import {useWS} from "../../../hooks/useWS.jsx";
import {useTranslation} from "react-i18next";
import {toast} from "react-toastify";
import {ListPresetSelect} from "../../../components/cm/ListPresetSelect.jsx";

function SelectReducer(state, action) {
    switch (action.type) {
        case 'TOGGLE_ID':
            return {
                ...state,
                [action.payload]: !(state[action.payload] || false)
            }
        case 'ADD_ALL':
            return {
                ...state,
                ...action.payload.reduce((acc, id) => {
                    acc[id] = false;
                    return acc;
                }, {})
            };
        case 'ADD_ID':
            return {
                ...state,
                [action.payload]: false
            };
        case 'CLEAR_ACTIVE':
            const newState = {...state};
            Object.keys(newState).forEach(id => {
                newState[id] = false;
            });
            return newState;
        case 'REMOVE_ACTIVE':
            const filteredState = {...state};
            Object.keys(filteredState).forEach(id => {
                if (filteredState[id]) {
                    delete filteredState[id];
                }
            });
            return filteredState;
        case 'REMOVE_IN':
            const filteredState2 = {...state};
            Object.keys(filteredState2).forEach(id => {
                if (action.payload.includes(id)) {
                    delete filteredState2[id];
                }
            });
            return filteredState2;
        case 'REMOVE_ID':
            const newState2 = {...state};
            delete newState2[action.payload];
            return newState2;
        case 'REMOVE_ALL':
            return {};
        default:
            return state;
    }
}

export function SelectCombModalContent({data, groups, setGroups, teamMode = false, defaultPreset = -1}) {
    const country = useCountries('fr')
    const {t} = useTranslation("cm");
    const {sendRequest, dispatch} = useWS()
    const [dispo, dispoReducer] = useReducer(SelectReducer, {})
    const [select, selectReducer] = useReducer(SelectReducer, {})
    const lastClick = useRef({time: 0, id: null});

    const [targetGroupe, setTargetGroupe] = useState("1")
    const [search, setSearch] = useState("")
    const [country_, setCountry_] = useState("")
    const [club, setClub] = useState("")
    const [gender, setGender] = useState({H: true, F: true, NA: true})
    const [cat, setCat] = useState(-1)
    const [weightMin, setWeightMin] = useState(0)
    const [weightMax, setWeightMax] = useState(0)
    const [team, setTeam] = useState(false)
    const [teamName, setTeamName] = useState("");
    const [preset, setPreset] = useState(-1)

    useEffect(() => {
        setPreset(defaultPreset)
    }, [defaultPreset])

    const handleSubmit = (e) => {
        e.preventDefault();
        if (teamMode) {
            toast.promise(
                sendRequest('setTeam', {
                    name: teamName,
                    members: [...Object.keys(select).map(id => Number(id))]
                }), getToastMessage("toast.team.update", "cm"))
                .then(res => {
                    if (res && res.id) {
                        setGroups(prev => [...prev.filter(d => d.id !== Number(res.id)), {id: Number(res.id), poule: targetGroupe}])
                    }
                })
        } else {
            setGroups(prev => [...prev.filter(d => select[d.id] === undefined), ...Object.keys(select).map(id => {
                return {id: Number(id), poule: targetGroupe}
            })])
        }

        dispoReducer({type: 'REMOVE_ALL'})
        selectReducer({type: 'REMOVE_ALL'})
        if (data == null)
            return
        dispoReducer({type: 'ADD_ALL', payload: data.map(d => d.id)})
    }


    useEffect(() => {
        const sendRegisterRemove = ({data}) => {
            dispoReducer({type: 'REMOVE_ID', payload: data})
            selectReducer({type: 'REMOVE_ID', payload: data})
        }
        dispatch({type: 'addListener', payload: {callback: sendRegisterRemove, code: 'sendRegisterRemove'}})
        return () => {
            dispatch({type: 'removeListener', payload: sendRegisterRemove})
        }
    }, []);

    useEffect(() => {
        if (data == null)
            return
        const selectedIds = Object.keys(select).map(g => Number(g))
        dispoReducer({type: 'ADD_ALL', payload: data.map(d => d.id).filter(id => !selectedIds.includes(id))})
    }, [data])

    useEffect(() => {
        if (data == null)
            return
        const teamIds = data.filter(d => d.teamMembers != null && d.teamMembers.length > 0).map(t => String(t.id));
        if (teamMode) {
            dispoReducer({type: 'REMOVE_IN', payload: teamIds});
            selectReducer({type: 'REMOVE_IN', payload: teamIds});
        } else {
            dispoReducer({type: 'ADD_ALL', payload: teamIds});
        }
    }, [teamMode])

    function applyFilter(dataIn, dataOut) {
        Object.keys(dataIn).forEach((id) => {
                const comb = data.find(d => d.id === Number(id));
                if (comb == null)
                    return;
                if ((search === "" || comb.fname.toLowerCase().includes(search.toLowerCase()) || comb.lname.toLowerCase().includes(search.toLowerCase())
                        || (comb.fname + " " + comb.lname).toLowerCase().includes(search.toLowerCase()))
                    && (country_ === "" || comb.country === country_)
                    && (club === "" || comb.club_str === club)
                    && (gender.H && comb.genre === 'H' || gender.F && comb.genre === 'F' || gender.NA && comb.genre === 'NA')
                    && (cat === -1 || cat === Math.min(CatList.length, CatList.indexOf(comb.categorie) + comb.overCategory))
                    && (weightMin === 0 || comb.weight !== null && comb.weight >= weightMin)
                    && (weightMax === 0 || comb.weight !== null && comb.weight <= weightMax)
                    && (teamMode && (comb.teamMembers == null || comb.teamMembers.length === 0) || !teamMode
                        && ((comb.teamMembers == null || comb.teamMembers.length === 0) !== team))
                    && (preset === -1 || comb.categoriesInscrites?.includes(preset))) {
                    dataOut[id] = dataIn[id];
                }
            }
        )
    }

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

    const dispoFiltered = {};
    applyFilter(dispo, dispoFiltered);

    const selectFiltered = {};
    applyFilter(select, selectFiltered);

    const moveComb = (event) => {
        event.preventDefault();
        switch (event.target.textContent) {
            case '>>':
                selectReducer({type: 'ADD_ALL', payload: Object.keys(dispoFiltered)})
                dispoReducer({type: 'REMOVE_IN', payload: Object.keys(dispoFiltered)});
                break;
            case '<<':
                dispoReducer({type: 'ADD_ALL', payload: Object.keys(selectFiltered)})
                selectReducer({type: 'REMOVE_IN', payload: Object.keys(selectFiltered)});
                break;
            case '>':
                selectReducer({type: 'ADD_ALL', payload: Object.keys(dispo).filter(id => dispo[id])})
                dispoReducer({type: 'REMOVE_ACTIVE'});
                break;
            case '<':
                dispoReducer({type: 'ADD_ALL', payload: Object.keys(select).filter(id => select[id])})
                selectReducer({type: 'REMOVE_ACTIVE'});
                break;
        }
    }

    return <>
        <div className="modal-header">
            <h1 className="modal-title fs-5" id="CategorieModalLabel">{t('select.sélectionnerDesCombatants')}{teamMode && (t('PourLéquipe'))}</h1>
            <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div className="modal-body">
            <div className="d-flex flex-wrap justify-content-around mb-1">
                <div className="col-md-5">
                    <label htmlFor="input4" className="form-label">{t('select.recherche')}</label>
                    <input type="text" className="form-control" id="input4" value={search} onChange={(e) => setSearch(e.target.value)}/>
                </div>

                <div style={{width: "12em"}}>
                    <label htmlFor="inputState0" className="form-label">{t('pays')}</label>
                    <select id="inputState0" className="form-select" value={country_} onChange={(e) => setCountry_(e.target.value)}>
                        <option value={""}>{t('--Tous--')}</option>
                        {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>

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

                <div>
                    <label htmlFor="inputState1" className="form-label">{t('club')}</label>
                    <select id="inputState1" className="form-select" value={club} onChange={(e) => setClub(e.target.value)}>
                        <option value={""}>{t('--Tous--')}</option>
                        {clubList.sort((a, b) => a.localeCompare(b)).map((club) => (
                            <option key={club} value={club}>{club}</option>))}
                    </select>
                </div>
            </div>

            <div className="d-flex flex-wrap justify-content-around mb-1">
                <div>
                    <label className="form-label">{t('genre')}</label>
                    <div className="d-flex align-items-center">
                        <div className="form-check" style={{marginRight: '10px'}}>
                            <input className="form-check-input" type="checkbox" id="gridCheck" checked={gender.H}
                                   onChange={e => setGender((prev) => {
                                       return {...prev, H: e.target.checked}
                                   })}/>
                            <label className="form-check-label" htmlFor="gridCheck">{t('genre.h')}</label>
                        </div>
                        <div className="form-check" style={{marginRight: '10px'}}>
                            <input className="form-check-input" type="checkbox" id="gridCheck2" checked={gender.F}
                                   onChange={e => setGender((prev) => {
                                       return {...prev, F: e.target.checked}
                                   })}/>
                            <label className="form-check-label" htmlFor="gridCheck2">{t('genre.f')}</label>
                        </div>
                        <div className="form-check">
                            <input className="form-check-input" type="checkbox" id="gridCheck3" checked={gender.NA}
                                   onChange={e => setGender((prev) => {
                                       return {...prev, NA: e.target.checked}
                                   })}/>
                            <label className="form-check-label" htmlFor="gridCheck3">{t('genre.na')}</label>
                        </div>
                    </div>
                </div>
                <div>
                    <label htmlFor="inputState2" className="form-label">{t('catégorie')}</label>
                    <select id="inputState2" className="form-select" value={cat} onChange={(e) => setCat(Number(e.target.value))}>
                        <option value={-1}>{t('--Tous--')}</option>
                        {CatList.map((cat, index) => {
                            return (<option key={index} value={index}>{getCatName(cat)}</option>)
                        })}
                    </select>
                </div>
                {!teamMode && <div>
                    <label className="form-label">{t('team')}</label>
                    <div className="d-flex align-items-center">
                        <div className="form-check" style={{marginRight: '10px'}}>
                            <input className="form-check-input" type="checkbox" id="gridCheck" checked={team}
                                   onChange={e => setTeam(e.target.checked)}/>
                            <label className="form-check-label" htmlFor="gridCheck">{t('team')}</label>
                        </div>
                    </div>
                </div>}
                <div>
                    <label htmlFor="input5" className="form-label">{t('poids')}</label>
                    <div className="row-cols-sm-auto d-flex align-items-center">
                        <div style={{width: "4.25em"}}><input type="number" className="form-control" id="input5" value={weightMin} min="0"
                                                              name="999"
                                                              onChange={e => setWeightMin(Number(e.target.value))}/></div>
                        <div><span>{t('select.à')}</span></div>
                        <div style={{width: "4.25em"}}><input type="number" className="form-control" value={weightMax} min="0" name="999"
                                                              onChange={e => setWeightMax(Number(e.target.value))}/></div>
                        <div><small>{t('select.msg1')}</small></div>
                    </div>
                </div>
                <button style={{display: "none"}} onClick={event => event.preventDefault()}></button>
            </div>
            <hr/>
            <div className="row g-3">
                <div className="col-md">
                    <div style={{textAlign: "center"}}>{t('inscrit')}</div>
                    <div className="list-group overflow-y-auto" style={{maxHeight: "50vh"}}>
                        {dispoFiltered && Object.keys(dispoFiltered).length === 0 && <div>{t('select.aucunCombattantDisponible')}</div>}
                        {Object.keys(dispoFiltered).sort((a, b) => nameCompare(data, a, b)).map((id) => (
                            <button key={id} type="button"
                                    className={"list-group-item list-group-item-action " + (dispoFiltered[id] ? "active" : "") + " " +
                                        (groups.find(g => g.id === Number(id) && g.poule !== '-') ? "list-group-item-secondary" : "")}
                                    onClick={() => {
                                        if (lastClick.current.id === id && (Date.now() - lastClick.current.time) < 500) {
                                            // Double click detected
                                            selectReducer({type: 'ADD_ID', payload: id})
                                            dispoReducer({type: 'REMOVE_ID', payload: id})
                                        } else {
                                            dispoReducer({type: 'TOGGLE_ID', payload: id})
                                        }
                                        lastClick.current = {time: Date.now(), id: id};
                                    }}>
                                <CombName combId={id}/>
                            </button>))}
                    </div>
                </div>
                <div className="col-auto" style={{margin: "0.5em auto"}}>
                    <div className="d-flex flex-sm-column align-items-center h-100 justify-content-center">
                        <button className="btn btn-secondary" style={{margin: "0.15em"}} onClick={moveComb}>&#62;&#62;</button>
                        <button className="btn btn-secondary" style={{margin: "0.15em"}} onClick={moveComb}>&#60;&#60;</button>
                        <button className="btn btn-secondary" style={{margin: "0.15em"}} onClick={moveComb}>&#62;</button>
                        <button className="btn btn-secondary" style={{margin: "0.15em"}} onClick={moveComb}>&#60;</button>
                    </div>
                </div>
                <div className="col-md">
                    <div style={{textAlign: "center"}}>{t('sélectionner')}</div>
                    <div className="list-group overflow-y-auto" style={{maxHeight: "50vh"}}>
                        {selectFiltered && Object.keys(selectFiltered).length === 0 && <div>{t('select.aucunCombattantSélectionné')}</div>}
                        {Object.keys(selectFiltered).sort((a, b) => nameCompare(data, a, b)).map((id) => (
                            <button key={id} type="button"
                                    className={"list-group-item list-group-item-action " + (selectFiltered[id] ? "active" : "")}
                                    onClick={() => {
                                        if (lastClick.current.id === id && (Date.now() - lastClick.current.time) < 500) {
                                            // Double click detected
                                            dispoReducer({type: 'ADD_ID', payload: id})
                                            selectReducer({type: 'REMOVE_ID', payload: id})
                                        } else {
                                            selectReducer({type: 'TOGGLE_ID', payload: id})
                                        }
                                        lastClick.current = {time: Date.now(), id: id};
                                    }}>
                                <CombName combId={id}/>
                            </button>))}
                    </div>
                </div>
            </div>
        </div>
        <div className="modal-footer">
            <button type="button" className="btn btn-secondary" data-bs-dismiss="modal">{t('fermer')}</button>
            <div className="vr"></div>
            {teamMode && <>
                <label htmlFor="input6" className="form-label">{t('nomDeLéquipe')}</label>
                <input type="text" className="form-control" id="input6" style={{width: "10em"}} value={teamName}
                       onChange={(e) => setTeamName(e.target.value)}/>
            </>}
            <label htmlFor="input7" className="form-label">{t('poule')}</label>
            <input type="text" className="form-control" id="input7" style={{width: "3em"}} maxLength={1} value={targetGroupe}
                   onChange={(e) => {
                       if (/^[a-zA-Z0-9]?/.test(e.target.value))
                           setTargetGroupe(e.target.value)
                   }}/>
            <button type="submit" className="btn btn-primary" data-bs-dismiss="modal" onClick={handleSubmit}
                    disabled={targetGroupe.length === 0 || (teamMode && teamName.length === 0)}>{t('ajouter')}</button>
        </div>
    </>
}

function nameCompare(data, a, b) {
    const combA = data.find(d => d.id === Number(a));
    const combB = data.find(d => d.id === Number(b));
    return (combA.fname + " " + combA.lname).toLowerCase().localeCompare((combB.fname + " " + combB.lname).toLowerCase());
}
