import Foundation

final class DealingTable: AbstractTable<DealingPlayer> {

    init(table: WaitingTable) {
        let cards = Dealer.dealFirstCards()
        let players = table.players.map(DealingPlayer.init)
        for (index, player) in players.enumerated() {
            player.cards = cards[index]
        }
        super.init(table: table, players: players)
    }

    /// All players either doubled or didn't double
    var allPlayersActed: Bool {
        !players.contains { !$0.didDecide }
    }

    /// At least one player placed a bid
    var hasDouble: Bool {
        players.contains { $0.didDouble }
    }

    override func perform(action: PlayerAction, forPlayer name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) {
        guard let player = players.player(named: name) else {
            print("Player \(name) unexpectedly missing from dealing table \(self.name)")
            return (.tableStateInvalid, nil)
        }
        guard player.canPerform(action) else {
            return (.tableStateInvalid, nil)
        }

        switch action {
        case .initialDoubleCost:
            return perform(double: true, forPlayer: player)
        case .noDoubleCost:
            return perform(double: false, forPlayer: player)
        default:
            return (.tableStateInvalid, nil)
        }
    }

    private func perform(double: Bool, forPlayer player: DealingPlayer) -> (result: PlayerActionResult, table: ManageableTable?) {
        guard !player.didDecide else {
            return (.tableStateInvalid, nil)
        }
        player.didDouble = double
        player.didDecide = true
        guard allPlayersActed else {
            return (.success, nil)
        }
        guard hasDouble else {
            // Revert to a waiting table and switch to the next player
            let table = WaitingTable(oldTableAdvancedByOne: self)
            return (.success, table)
        }
        // Automatically adds remaining cards to the players
        let table = BiddingTable(table: self)
        return (.success, table)
    }

    override func cards(forPlayerAt index: Int) -> [PlayableCard] {
        players[index].cards.unplayable
    }
}
