import * as log from '../util/logging.js'
import { UnoSession, UnoCard, UnoPlayer, } from './UnoSession.js';
import { UIVote } from './UiVote.js';

export function playCard(game: UnoSession, player: UnoPlayer, card: UnoCard, double?: UnoCard){
    log.logNotice("Player " + player.nickname + " (" + player.userId + ") plays card");
    let topCard = game.cardsPlayed[game.cardsPlayed.length - 1];
    //pr�fen ob spieler dran ist
    if (!(game.currentPlayer == player.userId)) {
        if(game.extraRules.sw_jumpin){
            //zwischenwerfen
            if ((topCard.number == card.number) && (topCard.color == card.color)) {
                game.cardsPlayed.push(card);
                game.clientRemoveCard(player,card);
                player.hand = player.hand.filter(el => el.id != card.id);
                let returnString = "Karte zwischengespielt";
                game.unoChat.writeMessage(player.nickname + ' hat eine ' +formatCard(card)+ ' <font color="#FF0000">zwischengespielt</font>.');
                if (player.hand.length == 1 && !player.uno) {
                    drawPlayer(game, 1);
                    returnString = "Karte zwischengespielt. Da du nicht UNO gesagt hast, musstest du eine Karte ziehen."
                    log.logNotice("Player " + player.nickname + " (" + player.userId + ") did not mention UNO. Add +2 Cards");
                    game.unoChat.writeMessage(player.nickname + " hat nicht UNO! gesagt und muss eine Karte ziehen.");
                }
                if (player.hand.length == 0 && player.uno) {
                    finishGame(game, player);
                }
                return [true, returnString]
            }else{
                return [false, "Du kannst diese Karte nicht einwerfen"]
            }
        }else{
            return [false, "Du bist nicht dran"]
        }
    }
    //pr�fen ob Karte passt
    if ((topCard.color == "select") || (topCard.color == card.color) || (topCard.number == card.number) || card.number == 'wild' || card.number == 'wild+4' || game.testmode) {
        //kann gelegt werden
        game.cardsPlayed.push(card);
        game.clientRemoveCard(player,card);
        player.hand = player.hand.filter(el => el.id != card.id);
        let returnString = "Karte gespielt";
        //double akti
        
        if(game.extraRules.sw_double && double){
            game.cardsPlayed.push(double);
            game.clientRemoveCard(player,double);
            player.hand = player.hand.filter(el => el.id != double.id);
            returnString = "Doppelt gespielt";
            game.unoChat.writeMessage(player.nickname + ' hat <font color="#FF0000">zwei</font> ' + formatCard(card)+ ' gelegt.');
            
        }
        if(game.extraRules.sw_double && !double){
            game.unoChat.writeMessage(player.nickname + ' hat eine ' + formatCard(card)+ ' gelegt.');
        }
        
        //uno pr�fen
        
        if (player.hand.length == 1 && !player.uno) {
            drawPlayer(game, 1);
            returnString = "Karte gespielt. Da du nicht UNO gesagt hast, musstest du eine Karte ziehen."
            log.logNotice("Player " + player.nickname + " (" + player.userId + ") did not mention UNO. Add +2 Cards");
            game.unoChat.writeMessage(player.nickname + " hat nicht UNO! gesagt und muss eine Karte ziehen.");
        }
        if (player.hand.length == 0 ) {
            finishGame(game, player);
        }
        //n�chster spieler
        advancePlayer(game, card.number == 'reverse', card.number == 'skip');

        if (card.number == '+2') {
            drawPlayer(game, 2);
            game.players.forEach((obj, ix) => {
                if (obj.userId == game.currentPlayer) {  game.unoChat.writeMessage(obj.nickname + " muss zwei Karten ziehen und setzt eine Runde aus.");}
            });
            advancePlayer(game, false, false);
        }
        if (card.number == 'wild+4') {
            drawPlayer(game, 4);
            game.players.forEach((obj, ix) => {
                if (obj.userId == game.currentPlayer) { game.unoChat.writeMessage(obj.nickname + " muss vier Karten ziehen und setzt eine Runde aus."); }
            });
            advancePlayer(game, false, false);
        }
        game.clientUpdatePlayedCard();
        return [true, returnString]
    } else {
        return [false, "Du kannst diese Karte hier nicht legen"]
    }
    
}

export function skip (game: UnoSession, player: UnoPlayer){
    log.logNotice("Player " + player.nickname + " (" + player.userId + ") skips card");
    game.unoChat.writeMessage(player.nickname + " setzt aus.");
    //pr�fen ob spieler dran ist
    if (!(game.currentPlayer == player.userId)) {
        return [false, "Du bist nicht dran"]
    }
    advancePlayer(game, false, false);
    return [true, "Ausgesetzt"]
}

export function pull(game: UnoSession, player: UnoPlayer) {
    log.logNotice("Player " + player.nickname + " (" + player.userId + ") pulls card");
    //pr�fen ob spieler dran ist
    if (!(game.currentPlayer == player.userId)) {
        return [false, "Du bist nicht dran"]
    }
    if (player.cardDrawn) {
        return [false, "Du hast bereits eine Karte gezogen"]
    }
    game.unoChat.writeMessage(player.nickname + " zieht eine Karte.");
    player.cardDrawn = true;
    let card = game.cardsMixed[game.cardsMixed.length - 1];
    game.cardsMixed.pop();
    log.logNotice("Pulled Card form Stack. Remaining: " + game.cardsMixed.length);
    game.clientAddCard(player,card);
    player.hand.push(card);
    player.uno = false;
    player.socket.send(JSON.stringify({
        changprop:"canskip",
        value: true,
    }))
    return [true, "Karte gezogen"]
}

export function uno(game: UnoSession, player: UnoPlayer) {
    log.logNotice("Player " + player.nickname + " (" + player.userId + ") says UNO");
    game.unoChat.writeMessage(player.nickname + " sagt UNO!");
    //pr�fen ob spieler dran ist
    if (!(game.currentPlayer == player.userId)) {
        return [false, "Du bist nicht dran"]
    }
    player.uno = true;
    return [true, "UNO!"]
}

export function leave(game: UnoSession, player: UnoPlayer) {
    log.logNotice("Player " + player.nickname + " (" + player.userId + ") leaves");
    game.unoChat.writeMessage(player.nickname + " verl�sst das Spiel.");
    player.hand.forEach((obj) => {
        game.cardsMixed = [obj, ...game.cardsMixed];
    });
    if (player.userId == game.currentPlayer) {
        advancePlayer(game, false, false);
    }
    player.socket.send(JSON.stringify({kick:"Spiel verlassen."}));
    game.players = game.players.filter(el => el.userId != player.userId);
    checkRestart(game);
}

export function onStart(game:UnoSession){
   
    if(game.extraRules.sw_sleep){
        game.startTimer(8,() => {
            let index = 0;
            game.players.forEach((obj, ix) => {
                if (obj.userId == game.currentPlayer) {index = ix;}
            });
            drawPlayer(game,1);
            game.clientNotify(game.players[index],'Du hast gepennt und musst einer Karte ziehen!',true);
            game.clientPlaySound(game.players[index],'../assets/skip.wav')
            game.unoChat.writeMessage(game.players[index].nickname + "hat gepennt und muss eine Karte ziehen");
            advancePlayer(game,false,false)
        })
    }
}

export function advancePlayer(game:UnoSession, change, skip) {

    let index = 0;
    game.players.forEach((obj, ix) => {
        if (obj.userId == game.currentPlayer) {index = ix;}
    });
    if(game.extraRules.sw_sleep){
        game.startTimer(8,() => {
            let index_sub = 0;
            game.players.forEach((obj, ix) => {
                if (obj.userId == game.currentPlayer) {index_sub = ix;}
            });
            drawPlayer(game,1);
            game.clientNotify(game.players[index_sub],'Du hast gepennt und musst einer Karte ziehen!',true);
            game.clientPlaySound(game.players[index_sub],'../assets/skip.wav')
            game.unoChat.writeMessage(game.players[index_sub].nickname + "hat gepennt und muss eine Karte ziehen");
            advancePlayer(game,false,false)
        })
    }
    game.players[index].cardDrawn = false; //temp werte resetten
    if (change) { game.direction = game.direction * -1 }
    let step = game.direction;
    if (skip) { step = step * 2 };
    let newIndex = index + step;
    if (newIndex < 0) { newIndex += game.players.length }
    if (newIndex > (game.players.length - 1)) { newIndex -= game.players.length }
    console.log(newIndex)
    game.currentPlayer = game.players[newIndex].userId;
    game.clientUpdateCurrentPlayer();
    checkStack(game);
    checkRestart(game);
}

function checkRestart(game:UnoSession) {
    if (game.players.length == 1) {
        log.logNotice("One Player Left. Restarting in 5s");
        game.unoChat.writeMessage("Ein Spieler verbleibend. Neustart in 5 Sekunden.");
        if(game.activeVote){game.activeVote.abortVote();}
        if(game.extraRules.sw_sleep){
            game.stopTimer();
        }
        setTimeout(() => { game.restartGame() }, 5000);
    }
}


function drawPlayer(game:UnoSession, amount) {
    let index = 0;
    game.players.forEach((obj, ix) => {
        if (obj.userId == game.currentPlayer) { index = ix; }
    });
    //draw for player
    for (let i = 0; i < amount; i++) {
        let card = game.cardsMixed[game.cardsMixed.length - 1];
        game.cardsMixed.pop();
        log.logNotice("Pulled Card form Stack. Remaining: " + game.cardsMixed.length);
        game.players[index].hand.push(card);
        game.clientAddCard(game.players[index],card);
    }
    game.clientUpdatePlayer(game.players[index]);
    return [true, ""]
}

function finishGame(game:UnoSession, player: UnoPlayer) {
    
    game.players.forEach((obj, ix) => {
        if (obj.userId == player.userId) {
            //TODO: Score berechnen
            player.score += getScore(game,player);
            game.clientRemovePlayer(player)
            game.clientUpdateWinner();
            game.winners.push(obj)
            game.unoChat.writeMessage(obj.nickname + " hat die Runde beendet.");

        }
    });
    game.clientRemovePlayer(player);
    game.clientUpdateWinner();
    game.players = game.players.filter(el => el.userId != player.userId);
    
    voteEarlyFinish(game);
}

function checkStack(game:UnoSession) {
    //remix stack
    if (game.cardsPlayed.length > 10) {
        log.logNotice("Remix played cards");
        game.unoChat.writeMessage("Karten werden neu gemischt.");
        for (let i = 0; i < game.cardsPlayed.length - 2; i++) {
            let card = game.cardsPlayed[i];
            game.cardsMixed.push(game.cardsPlayed[i]);
            console.log(game.cardsMixed.length)
            
        }
        game.cardsPlayed = [game.cardsPlayed[game.cardsPlayed.length - 1]];

        game.cardsMixed.sort(() => Math.random() - 0.5);
        game.cardsMixed.sort(() => Math.random() - 0.5);
        game.cardsMixed.sort(() => Math.random() - 0.5);
    }

}

function getScore(game:UnoSession, player: UnoPlayer) {
    let score = 0;
    game.players.forEach(pl => {
        if (pl.userId != player.userId && game.winners.length == 0) {
            pl.hand.forEach(card => {
                switch (card.number) {
                    case 'wild':
                        score += 50;
                        break;
                    case 'wild+4':
                        score += 50;
                        break;
                    case '+2':
                        score += 20;
                        break;
                    case 'reverse':
                        score += 20;
                        break;
                    case 'skip':
                        score += 20;
                        break;
                    default:
                        break;
                }
            })
        }
    })
    return score;
}

function voteEarlyFinish(game: UnoSession){
    game.activeVote = new UIVote(game,'Vorzeitig beenden',8000);
    game.activeVote.addQuestion("Soll die Runde vorzeitig beendet werden?",["Ja","Nein"]);
    game.activeVote.startVote((values)=>{
        console.log("Vote results", values);
        if (values[0].counter[0] > values[0].counter[1]){
            game.unoChat.writeMessage("Abstimmung erfolgreich. Nächste Runde wird gestartet.")
            game.restartGame();
        }
    })
}

function formatCard(card: UnoCard){
    let color = ''
    let number = ''
    switch(card.color){
        case 'red': color='<font color="#ed1c24">Rote</font>'; break;
        case 'blue': color='<font color="#0095da">Blaue</font>'; break;
        case 'green': color='<font color="#00ab67">Grüne</font>'; break;
        case 'yellow': color='<font color="#ffde00">Gelbe</font>'; break;
    }

    switch(card.number){
        case '+2': number='<font color="#FFFACD">Zieh Zwei Karte</font>'; break;
        case 'reverse': number='<font color="#FFFACD">Retoure Karte</font>'; break;
        case 'skip': number='<font color="#FFFACD">Aussetzen Karte</font>'; break;
        case 'wild': number='<font color="#F08080">Farbwahlkarte</font>'; break;
        case 'wild+4': number='<font color="#F08080">Zieh Vier Farbwahlkarte</font>'; break;
        default: number = card.number.toString();
    }

    return color + ' ' + number 

}

