import {useWS} from "../../../hooks/useWS.jsx";
import {useEffect, useReducer, useRef, useState} from "react";
import {useCards, useCardsDispatch} from "../../../hooks/useCard.jsx";
import {from_sendTree} from "../../../utils/TreeUtils.js";
import {MarchReducer} from "../../../utils/MatchReducer.jsx";
import {CombName, useCombsDispatch} from "../../../hooks/useComb.jsx";
import {timePrint, win_end} from "../../../utils/Tools.js";

function reducer(state, action) {
    switch (action.type) {
        case 'SET':
            return [...state.filter(s => s.id !== action.payload.id), action.payload]
        case 'SET_ALL':
            return action.payload
        case 'REMOVE':
            return state.filter(s => s.id !== action.payload)
        default:
            return state
    }
}

export function useTablesState() {
    const {sendRequest, dispatch} = useWS();
    const [state, dispatchState] = useReducer(reducer, [])

    const subscribeToState = () => {
        sendRequest("subscribeToState", true)
            .then((data) => {
                dispatchState({type: 'SET_ALL', payload: data});
            })
    }

    useEffect(() => {
        const sendStateFull = ({data}) => {
            dispatchState({type: 'SET', payload: data});
        }

        const rmStateFull = ({data}) => {
            dispatchState({type: 'REMOVE', payload: data});
        }

        const welcomeInfo = () => {
            subscribeToState();
        }
        subscribeToState();

        dispatch({type: 'addListener', payload: {callback: welcomeInfo, code: 'welcomeInfo'}})
        dispatch({type: 'addListener', payload: {callback: sendStateFull, code: 'sendStateFull'}})
        dispatch({type: 'addListener', payload: {callback: rmStateFull, code: 'rmStateFull'}})
        return () => {
            dispatch({type: 'removeListener', payload: welcomeInfo});
            dispatch({type: 'removeListener', payload: sendStateFull});
            dispatch({type: 'removeListener', payload: rmStateFull});

            sendRequest("subscribeToState", false)
                .then(() => {
                });
        }
    }, [])

    return {state};
}

export function StateWindow({document}) {
    const {state} = useTablesState();

    document.title = "État des tables de marque";
    document.body.className = "overflow-hidden";

    console.log(state)
    return <>
        <div className="d-flex flex-row flex-wrap justify-content-around align-items-center align-content-around h-100 p-2 overflow-auto">
            {state.sort((a, b) => a.liceName.localeCompare(b.liceName)).map((table, index) =>
                <div key={index} className="card d-inline-flex flex-grow-1 align-self-stretch" style={{minWidth: "25em", maxWidth: "30em"}}>
                    <ShowState table={table}/>
                </div>)
            }
        </div>
    </>
}

function readAndConvertMatch(matches, data, combsToAdd) {
    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
    })
    if (data.c1)
        combsToAdd.push(data.c1)
    if (data.c2)
        combsToAdd.push(data.c2)
}

function ShowState({table}) {
    const cardDispatch = useCardsDispatch();
    const {sendRequest, dispatch} = useWS();
    const [matches, reducer] = useReducer(MarchReducer, []);
    const combDispatch = useCombsDispatch();
    const {cards_v} = useCards();

    const [cat, setCat] = useState({id: -1, name: ""});

    const marches2 = matches.filter(m => m.categorie === cat.id).map(m => ({...m, ...win_end(m, cards_v)}))

    useEffect(() => {
        const categoryListener = ({data}) => {
            if (data.id !== cat.id)
                return;
            setCat({id: data.id, name: data.name});
        }

        const matchListener = ({data: datas}) => {
            for (const data of datas) {
                reducer({type: 'UPDATE_OR_ADD', payload: {...data, c1: data.c1?.id, c2: data.c2?.id}});
                combDispatch({type: 'SET_ALL', payload: {source: "match", data: [data.c1, data.c2].filter(d => d != null)}});
            }
        }

        const deleteMatch = ({data: datas}) => {
            for (const data of datas)
                reducer({type: 'REMOVE', payload: data});
        }

        dispatch({type: 'addListener', payload: {callback: categoryListener, code: 'sendCategory'}})
        dispatch({type: 'addListener', payload: {callback: matchListener, code: 'sendMatch'}})
        dispatch({type: 'addListener', payload: {callback: deleteMatch, code: 'sendDeleteMatch'}})
        return () => {
            dispatch({type: 'removeListener', payload: matchListener})
            dispatch({type: 'removeListener', payload: deleteMatch})
            dispatch({type: 'removeListener', payload: categoryListener})
        }
    }, []);

    useEffect(() => {
        if (table.selectedCategory !== cat.id) {
            if (!table.selectedCategory || table.selectedCategory === -1) {
                setCat({id: -1, name: ""});
                return;
            }
            sendRequest('getFullCategory', table.selectedCategory)
                .then((data) => {
                    setCat({id: data.id, name: data.name});
                    cardDispatch({type: 'SET_ALL', payload: data.cards});

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

                    reducer({type: 'REPLACE_ALL', payload: matches2});
                    combDispatch({type: 'SET_ALL', payload: {source: "match", data: combsToAdd}});
                    console.log(matches2);
                })
        }
    }, [table]);

    return <>
        <div className="card-header">
            Zone de combat {table.liceName}
        </div>
        <div className="card-body">
            Catégorie : {cat.name}<br/>
            Match terminés : {marches2.filter(m => m.end).length}/{marches2.length}<br/>
            Matchs : <PrintMatch match={matches.find(m => m.id === table.selectedMatch)}/><br/>
            Statue : {table?.state}<br/>
            Score : {table?.scoreState?.scoreRouge} - {table?.scoreState?.scoreBleu}<br/>
            Chronomètre : <PrintChrono chrono={table?.chronoState}/><br/>
        </div>
    </>
}

function PrintMatch({match}) {
    return <>{match?.c1 && <CombName combId={match?.c1}/>} vs {match?.c2 && <CombName combId={match?.c2}/>}</>
}


function PrintChrono({chrono}) {
    const chronoText = useRef(null)
    const state = useRef({chronoState: 0, countBlink: 20, lastColor: "#000000", lastTimeStr: "00:00"})

    const isRunning = () => chrono.startTime !== 0
    const getTime = () => {
        if (chrono.startTime === 0)
            return chrono.time
        return chrono.time + Date.now() - chrono.startTime
    }

    useEffect(() => {
        if (!chrono || !chronoText.current)
            return;

        const state_ = state.current
        const text_ = chronoText.current

        const timer = setInterval(() => {
            let currentDuration = chrono.configTime
            if (chrono.state === 2) {
                currentDuration = chrono.configPause
            }
            const timeStr = (chrono.state === 1 ? " Match - " : " Pause - ") + timePrint(currentDuration - getTime()) + (isRunning() ? "" : " (arrêté)")

            if (timeStr !== state_.lastTimeStr) {
                text_.textContent = timeStr
                state_.lastTimeStr = timeStr
            }

            if (chrono.chronoState === 0) {
                clearInterval(timer)
            }
        }, 50);
        return () => clearInterval(timer)
    }, [chrono])

    return <><span ref={chronoText}>{state.current.lastTimeStr}</span></>
}
