import "./tile.js";

class Group {
    constructor(tiles, stollenTile = null, dir = null) {
        this.tiles = tiles;
        this.stollenTile = stollenTile;
        this.dir = dir; // 1 for left, 2 for middle, 3 for right
    }
}

class Hand {
    constructor(tiles = []) {
        this.tiles = tiles;
        this.groups = [];
        this.drawn= null;
    }

    drawTile(tile) {
        this.drawn = tile;
    }

    discard(k) {
        if (k === this.tiles.length) {
            const tile = this.drawn;
            this.drawn = null;
            return tile;
        } else {
            const tile = this.tiles[k];
            this.tiles.splice(k, 1);
            return tile;
        }
    }

    sort() {
        this.tiles.sort((a, b) => {
            if (a.lessThan(b)) return -1;
            if (b.lessThan(a)) return 1;
            return 0;
        });
    }

    shuffle() {
        for (let i = this.tiles.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [this.tiles[i], this.tiles[j]] = [this.tiles[j], this.tiles[i]];
        }
    }

    flatten() {
        if (this.drawn) {
            this.tiles.push(this.drawn);
        }
        this.drawn = null;
        this.sort();
    }

    makeGroup(tiles, stollenTile = null, dir = null) {
        const group = new Group(tiles, stollenTile, dir);
        this.groups.push(group);
        for (let tile of tiles) {
            const index = this.tiles.findIndex(t => t.equals(tile));
            if (index !== -1) {
                this.tiles.splice(index, 1);
            }
        }
        this.flatten();
    }
}

class Draw {
    constructor() {
        this.tiles = Tile.generateAll();
        this.shuffle();
    }

    shuffle() {
        for (let i = this.tiles.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [this.tiles[i], this.tiles[j]] = [this.tiles[j], this.tiles[i]];
        }
    }

    drawTile() {
        return this.tiles.pop();
    }

    drawHand() {
        const handTiles = [];
        for (let i = 0; i < 13; i++) {
            handTiles.push(this.drawTile());
        }
        return new Hand(handTiles);
    }
}

class Discard {
    constructor() {
        this.tiles = [];
        this.hiddenTiles = [];
    }

    add(tile) {
        this.tiles.push(tile);
    }

    beeingStollen() {
        this.hiddenTiles.push(this.tiles.pop());
        return this.hiddenTiles[this.hiddenTiles.length - 1];
    }

    isIn(tile) {
        return this.tiles.some(t => t.equals(tile)) || this.hiddenTiles.some(t => t.equals(tile));
    }
}

class Game {
    constructor(skipInitialDeal = false) {
        this.discards = [
            new Discard(),
            new Discard(),
            new Discard(),
            new Discard()
        ];
        this.wall = new Draw();
        
        if (skipInitialDeal) {
            this.hands = [
                new Hand(),
                new Hand(),
                new Hand(),
                new Hand()
            ];
        } else {
            this.hands = [
                this.wall.drawHand(),
                this.wall.drawHand(),
                this.wall.drawHand(),
                this.wall.drawHand()
            ];
            for (let hand of this.hands) {
                hand.sort();
            }
        }
        
        this.firstDealer = Math.floor(Math.random() * 4) * 0;
        this.turn = this.firstDealer;
        this.repeat = 0;

        if (!skipInitialDeal) {
            this.draw(this.turn);
        }
    }

    newDeal(hasRepeat = false) {
        this.discards = [
            new Discard(),
            new Discard(),
            new Discard(),
            new Discard()
        ];
        this.wall = new Draw();
        this.hands = [
            this.wall.drawHand(),
            this.wall.drawHand(),
            this.wall.drawHand(),
            this.wall.drawHand()
        ];
        if (!hasRepeat) {
            this.turn = (this.firstDealer + 1) % 4;
        } else {
            this.repeat++;
        }
    }

    nextTurn() {
        this.turn = (this.turn + 1) % 4;
    }

    draw(player) {
        this.hands[player].drawTile(this.wall.drawTile());
    }

    discard(player, k) {
        if (player === this.turn) {
            const tile = this.hands[player].discard(k);
            this.discards[player].add(tile);
            this.hands[player].flatten();
        }
    }

    chii(player, tiles, dir) {
        const hand = this.hands[player];
        dir = (player - this.turn) % 4;
        console.assert(dir == 1);
        this.hands[player].makeGroup(tiles, this.discards[this.turn].beeingStollen(), dir);
    }

    pon(player, tiles, dir) {
        const hand = this.hands[player];
        dir = (player - this.turn + 4) % 4;
        console.assert(dir == 1 || dir == 2 ||dir == 3, `Invalid direction: ${dir}`);
        this.hands[player].makeGroup(tiles, this.discards[this.turn].beeingStollen(), dir);
    }

    canPon(player) {
        const lastTile = this.discards[this.turn].tiles[this.discards[this.turn].tiles.length - 1];
        return this.hands[player].tiles.filter(t => t.equals(lastTile)).length >= 2;
    }

    botPlay() {
        // Le bot défausse une tuile au hasard (supposant qu'il a déjà pioché)
        const hand = this.hands[this.turn];
        const randomIndex = Math.floor(Math.random() * (hand.tiles.length + (hand.drawn ? 1 : 0)));
        this.discard(this.turn, randomIndex);
    }
}

export { Discard, Draw, Game, Group, Hand };

