import chess
import random
from IPython.display import display, HTML, clear_output
import time

class ChessPlayer(object):
    def __init__(self, code, name, rating=1400):
        self.code = code
        self.rating = rating
        self.name = name

    def __repr__(self):
        return "<ChessPlayer %s: %s>" % (self.name, self.rating)

    def play(self, other, visual=None):
        """
        Play a chess game with the other, and 
        adjust both of your scores.
        """
        ## result = 0.0 - lose, 0.5 - draw, 1.0 - win
        if random.random() < .5:
            # (True|False|None, "message", board)
            results = play_game(self.code, other.code, visual)
            if results[0] is True:
                result = 1.0
                results.append(self.name)
            elif results[0] is False:
                result = 0.0
                results.append(other.name)
            elif results[0] is None:
                result = 0.5
                results.append([self.name, other.name])
            mycolor = "WHITE"
        else:
            results = play_game(other.code, self.code, visual)
            if results[0] is True:
                result = 0.0
                results.append(other.name)
            elif results[0] is False:
                result = 1.0
                results.append(self.name)
            elif results[0] is None:
                result = 0.5
                results.append([self.name, other.name])
            mycolor = "BLACK"
        expected_score = self.get_expected_score(other.rating)
        self.adjust_rating(expected_score, result)
        other.adjust_rating(1.0 - expected_score, 1.0 - result)
        print("I am", mycolor, "name", self.name, self.rating)
        print("Other", other.name, other.rating)
        return results

    def get_expected_score(self, other_rating):
        return 1.0 /(1 + 10 ** ((other_rating - self.rating)/400.0))

    def adjust_rating(self, expected_score, score, k=32):
        self.rating += int(round(k * (score - expected_score)))

def display_board(board, use_svg):
    if use_svg:
        return board._repr_svg_()
    else:
        return "<pre>" + str(board) + "</pre>"

def who(player):
    return "White" if player == chess.WHITE else "Black"

def play_game(player1, player2, visual="svg", pause=0.1):
    """
    playerN1, player2: functions that takes board, return uci move
    visual: "simple" | "svg" | None
    """
    use_svg = (visual == "svg")
    board = chess.Board()
    try:
        while not board.is_game_over(claim_draw=True):
            if board.turn == chess.WHITE:
                uci = player1(board)
            else:
                uci = player2(board)
            name = who(board.turn)
            board.push_uci(uci)
            board_stop = display_board(board, use_svg)
            html = "<b>Move %s %s, Play '%s':</b><br/>%s" % (
                       len(board.move_stack), name, uci, board_stop)
            if visual is not None:
                if visual == "svg":
                    clear_output(wait=True)
                display(HTML(html))
                if visual == "svg":
                    time.sleep(pause)
    except KeyboardInterrupt:
        msg = "Game interrupted!"
        return (None, msg, board)
    result = None
    if board.is_checkmate():
        msg = "checkmate: " + who(not board.turn) + " wins!"
        result = not board.turn
    elif board.is_stalemate():
        msg = "draw: stalemate"
    elif board.is_fivefold_repetition():
        msg = "draw: 5-fold repetition"
    elif board.is_insufficient_material():
        msg = "draw: insufficient material"
    elif board.can_claim_draw():
        msg = "draw: claim"
    if visual is not None:
        print(msg)
    return [result, msg, board]
