export function punteggio(striscia) {
    let home = 0, guest = 0
    for (const c of striscia.at(-1).ris) c === 'h' ? home++ : guest++
    return { home, guest }
}

export function servizio(striscia) {
    const set = striscia.at(-1)
    return set.ris.length === 0 ? set.serv === 'h' : set.ris.at(-1) === 'h'
}

export function setVinti(striscia) {
    return {
        home:  striscia.filter(s => s.vinc === 'h').length,
        guest: striscia.filter(s => s.vinc === 'g').length,
    }
}

export function createInitialState() {
    return {
        order: true,
        visuForm: false,
        visuStriscia: true,
        timeout: false,
        timeoutTeam: null,
        timeoutVideo: null,
        timeoutStartedAt: null,
        modalitaPartita: "3/5",
        sp: {
            striscia: [{ serv: 'h', ris: '', vinc: null }],
            nomi: { home: "Antoniana", guest: "Guest" },
            form: {
                home: ["1", "2", "3", "4", "5", "6"],
                guest: ["1", "2", "3", "4", "5", "6"],
            },
        },
    }
}

export function checkVittoria(state) {
    const { home: puntHome, guest: puntGuest } = punteggio(state.sp.striscia)
    const sv = setVinti(state.sp.striscia)
    const totSet = sv.home + sv.guest
    const isSetDecisivo = state.modalitaPartita === "2/3" ? totSet >= 2 : totSet >= 4
    const punteggioVittoria = isSetDecisivo ? 15 : 25

    if (puntHome >= punteggioVittoria && puntHome - puntGuest >= 2) return true
    if (puntGuest >= punteggioVittoria && puntGuest - puntHome >= 2) return true
    return false
}

export function checkVittoriaPartita(state) {
    if (state.modalitaPartita === 'amichevole') return false
    const setsToWin = state.modalitaPartita === "2/3" ? 2 : 3
    const sv = setVinti(state.sp.striscia)
    return sv.home >= setsToWin || sv.guest >= setsToWin
}

export function applyAction(state, action) {
    const s = structuredClone(state)

    switch (action.type) {
        case "incPunt": {
            const team = action.team
            if (checkVittoria(s)) break

            const servHome = servizio(s.sp.striscia)
            const cambioPalla = (team === "home") !== servHome
            const setCorrente = s.sp.striscia.at(-1)
            if (setCorrente.ris === '') {
                setCorrente.formInizio = {
                    home: [...s.sp.form.home],
                    guest: [...s.sp.form.guest],
                }
            }
            s.sp.striscia.at(-1).ris += team === 'home' ? 'h' : 'g'

            if (cambioPalla) {
                s.sp.form[team].push(s.sp.form[team].shift())
            }
            break
        }

        case "decPunt": {
            const currentSet = s.sp.striscia.at(-1)
            if (currentSet.ris.length === 0) break

            const lastScorerShort = currentSet.ris.at(-1)
            const prevServerShort = currentSet.ris.length >= 2
                ? currentSet.ris.at(-2)
                : currentSet.serv

            const wasCambioPalla = lastScorerShort !== prevServerShort

            currentSet.ris = currentSet.ris.slice(0, -1)
            if (currentSet.ris === '') delete currentSet.formInizio

            const lastScorer = lastScorerShort === 'h' ? 'home' : 'guest'

            if (wasCambioPalla) {
                s.sp.form[lastScorer].unshift(s.sp.form[lastScorer].pop())
            }
            break
        }

        case "incSet": {
            const team = action.team
            const sv = setVinti(s.sp.striscia)
            const count = sv[team]
            const teamShort = team === 'home' ? 'h' : 'g'
            if (count >= 2) {
                // cicla a 0: rimuove le voci fantasma per questo team
                s.sp.striscia = s.sp.striscia.filter(
                    entry => !(entry._phantom && entry.vinc === teamShort)
                )
            } else {
                // inserisce una voce fantasma prima dell'ultimo set (quello in corso)
                s.sp.striscia.splice(-1, 0, { serv: teamShort, ris: '', vinc: teamShort, _phantom: true })
            }
            break
        }

        case "nuovoSet": {
            const team = action.team
            if (team !== 'home' && team !== 'guest') break
            if (checkVittoriaPartita(s)) break
            s.sp.striscia.at(-1).vinc = team === 'home' ? 'h' : 'g'
            if (checkVittoriaPartita(s)) break
            s.sp.striscia.push({ serv: team === 'home' ? 'h' : 'g', ris: '', vinc: null })
            s.sp.form = {
                home: ["1", "2", "3", "4", "5", "6"],
                guest: ["1", "2", "3", "4", "5", "6"],
            }
            break
        }

        case "cambiaPalla": {
            const currentSet = s.sp.striscia.at(-1)
            if (currentSet.ris.length === 0) {
                currentSet.serv = currentSet.serv === 'h' ? 'g' : 'h'
            }
            break
        }

        case "resetta": {
            s.visuForm = false
            const servIniziale = s.sp.striscia[0]?.serv ?? 'h'
            s.sp.striscia = [{ serv: servIniziale, ris: '', vinc: null }]
            s.sp.form = {
                home: ["1", "2", "3", "4", "5", "6"],
                guest: ["1", "2", "3", "4", "5", "6"],
            }
            break
        }

        case "toggleFormazione": {
            s.visuForm = !s.visuForm
            break
        }

        case "toggleStriscia": {
            s.visuStriscia = !s.visuStriscia
            break
        }

        case "toggleOrder": {
            s.order = !s.order
            break
        }

        case "startTimeout": {
            const team = action.team
            if (team !== 'home' && team !== 'guest') break
            if (!s.timeout) {
                const setCorrente = s.sp.striscia.at(-1)
                ;(setCorrente.timeouts ??= []).push({
                    team,
                    punteggio: punteggio(s.sp.striscia),
                })
            }
            s.timeout = true
            s.timeoutTeam = team
            s.timeoutVideo = action.video ?? null
            s.timeoutStartedAt = action.startedAt ?? null
            break
        }

        case "stopTimeout": {
            s.timeout = false
            s.timeoutTeam = null
            s.timeoutVideo = null
            s.timeoutStartedAt = null
            break
        }

        case "setNomi": {
            if (action.home !== undefined) s.sp.nomi.home = action.home
            if (action.guest !== undefined) s.sp.nomi.guest = action.guest
            break
        }

        case "setModalita": {
            s.modalitaPartita = action.modalita
            break
        }

        case "setFormazione": {
            if (action.team && action.form) {
                s.sp.form[action.team] = [...action.form]
            }
            break
        }

        case "confermaCambi": {
            const team = action.team
            const cambi = action.cambi || []
            const form = s.sp.form[team].map((val) => String(val).trim())
            const formAggiornata = [...form]
            const cambiApplicati = []

            let valid = true
            for (const cambio of cambi) {
                const cin = (cambio.in || "").trim()
                const cout = (cambio.out || "").trim()
                if (!cin || !cout) continue
                if (!/^\d+$/.test(cin) || !/^\d+$/.test(cout)) { valid = false; break }
                if (cin === cout) { valid = false; break }
                if (formAggiornata.includes(cin)) { valid = false; break }
                if (!formAggiornata.includes(cout)) { valid = false; break }

                const idx = formAggiornata.findIndex((val) => String(val).trim() === cout)
                if (idx !== -1) {
                    formAggiornata.splice(idx, 1, cin)
                    cambiApplicati.push({ in: cin, out: cout })
                }
            }

            if (valid) {
                s.sp.form[team] = formAggiornata
                if (cambiApplicati.length > 0) {
                    const setCorrente = s.sp.striscia.at(-1)
                    const puntAttuale = punteggio(s.sp.striscia)
                    ;(setCorrente.cambi ??= []).push(
                        ...cambiApplicati.map(c => ({ team, ...c, punteggio: { ...puntAttuale } }))
                    )
                }
            }
            break
        }

        default:
            break
    }

    return s
}
