import Foundation
import WebSocketKit

class Player {

    let name: PlayerName

    var socket: WebSocket?

    var isNextActor: Bool

    init(name: PlayerName, socket: WebSocket? = nil) {
        self.name = name
        self.socket = socket
        self.isNextActor = false
    }

    init(player: Player) {
        self.name = player.name
        self.socket = player.socket
        self.isNextActor = false
    }

    var actions: [PlayerAction] {
        []
    }

    var states: [PlayerState] {
        isConnected ? [] : [.isDisconnected]
    }

    var info: PlayerInfo {
        var result = PlayerInfo(name: name)
        result.isConnected = isConnected
        result.isNextActor = isNextActor
        result.state = states.map { $0.rawValue }
        return result
    }
}

extension Player: Equatable {

    static func == (lhs: Player, rhs: Player) -> Bool {
        lhs.name == rhs.name
    }
}

extension Player {

    // MARK: Connection

    /// Indicate that the player is connected when at a table
    var isConnected: Bool {
        guard let socket = socket else {
            return false
        }
        guard !socket.isClosed else {
            self.socket = nil
            return false
        }
        return true
    }

    func connect(using socket: WebSocket) {
        _ = self.socket?.close()
        self.socket = socket
    }

    @discardableResult
    func disconnect() -> Bool {
        guard let socket = socket else {
            return false
        }
        socket.close().whenFailure { [weak self] error in
            print("Failed to close socket for player: \(self?.name ?? "<Released>"): \(error)")
        }
        self.socket = nil
        return true
    }


    @discardableResult
    func send(_ info: TableInfo) -> Bool {
        guard let socket = socket else {
            return false
        }
        do {
            try socket.send(encodeJSON(info))
        } catch {
            print("Failed to send info: \(error)")
            return false
        }
        return true
    }

    // MARK: Actions

    func canPerform(_ action: PlayerAction) -> Bool {
        actions.contains(action)
    }

}

extension Player: CustomStringConvertible {

    var description: String {
        name
    }
}
