import curses
import chess
import chess.engine
import os
import random

# Initialize Stockfish engine
stockfish_path = "/usr/games/stockfish"
engine = chess.engine.SimpleEngine.popen_uci(stockfish_path)

# Define ASCII/Nerd Font pieces
PIECE_SYMBOLS = {
    'P': '♙', 'N': '♘', 'B': '♗', 'R': '♖', 'Q': '♕', 'K': '♔',
    'p': '♟', 'n': '♞', 'b': '♝', 'r': '♜', 'q': '♛', 'k': '♚'
}

def draw_board(stdscr, board, cell_width, cell_height, start_y, start_x, selected_square=None, move_history=[], legal_moves=[], player_color=None):
    stdscr.clear()
    
    max_y, max_x = stdscr.getmaxyx()
    
    # Draw the move history
    move_history_y = 2
    stdscr.addstr(0, 0, "Move History:")
    for index, move in enumerate(move_history[-(max_y // 2 - 2):]):  # Display limited history
        stdscr.addstr(move_history_y + index, 0, move)
    
    # Draw the chessboard oriented towards the player
    for board_y in range(8):
        actual_row = board_y if player_color == chess.BLACK else 7 - board_y  # Orient the row correctly based on player color
        for board_x in range(8):
            actual_col = board_x if player_color == chess.WHITE else 7 - board_x  # Orient the column correctly
            
            piece = board.piece_at(chess.square(actual_col, actual_row))
            display_piece = PIECE_SYMBOLS[piece.symbol()] if piece else ' '
            
            # Determine square color
            square_color = curses.color_pair(1) if (actual_row + actual_col) % 2 == 0 else curses.color_pair(2)
            is_selected = (selected_square == chess.square(actual_col, actual_row))
            is_legal_move = chess.square(actual_col, actual_row) in legal_moves

            if is_selected:
                square_color = curses.color_pair(3)  # Highlight selected square
            elif is_legal_move:
                square_color = curses.color_pair(4)  # Highlight legal move square
            
            stdscr.attron(square_color)
            
            # Ensure that the piece is drawn centered in the cell
            for line in range(cell_height):
                if line == cell_height // 2:  # Only draw the piece on the middle line
                    cell_content = display_piece.center(cell_width)
                else:
                    cell_content = ' ' * cell_width  # Clear remaining lines in the cell
                
                try:
                    stdscr.addstr(start_y + board_y * cell_height + line, start_x + board_x * cell_width, cell_content)
                except curses.error:
                    pass
                
            stdscr.attroff(square_color)
    
    stdscr.refresh()

def get_square_from_position(mouse_x, mouse_y, cell_width, cell_height, start_x, start_y, player_color):
    row = (mouse_y - start_y) // cell_height
    col = (mouse_x - start_x) // cell_width
    if player_color == chess.BLACK:
        col = 7 - col  # Reverse column for black orientation
    if player_color == chess.WHITE:
        row = 7 - row  # Reverse row for white orientation
    if 0 <= row < 8 and 0 <= col < 8:
        return chess.square(col, row)
    return None

def main(stdscr):
    curses.curs_set(0)
    stdscr.clear()
    curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
    curses.start_color()
    curses.init_pair(1, curses.COLOR_WHITE, 94)   # Light brown background
    curses.init_pair(2, curses.COLOR_BLACK, 58)   # Dark brown background
    curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)  # Highlight selected square in grey
    curses.init_pair(4, curses.COLOR_GREEN, curses.COLOR_WHITE)   # Highlight legal move square

    # Get difficulty input
    stdscr.addstr(0, 0, "Enter difficulty level (1-20): ")
    stdscr.refresh()
    while True:
        try:
            difficulty_input = stdscr.getstr().decode().strip()
            difficulty = int(difficulty_input)
            if 1 <= difficulty <= 20:
                break
            else:
                stdscr.addstr(1, 0, "Invalid input. Please enter a number between 1 and 20.")
        except ValueError:
            stdscr.addstr(1, 0, "Invalid input. Please enter a valid integer.")
        
        stdscr.refresh()
        stdscr.getch()
        stdscr.clear()
        stdscr.addstr(0, 0, "Enter difficulty level (1-20): ")

    # Randomly assign player color
    player_color = chess.WHITE if random.choice([True, False]) else chess.BLACK
    player_side = "White" if player_color == chess.WHITE else "Black"
    stdscr.clear()
    stdscr.addstr(0, 0, f"You are playing as: {player_side}")
    stdscr.refresh()
    stdscr.getch()
    
    board = chess.Board()
    move_history = []
    undo_stack = []
    redo_stack = []
    cell_width = 5  # Adjusted size for larger icons
    cell_height = 3
    selected_square = None
    piece_selected = False
    moving_mode = False
    legal_moves = []
    original_square = None
    
    while True:
        rows, cols = stdscr.getmaxyx()
        cell_width = max(5, min(6, (cols - 20) // 16))  # Ensure room for the move history
        cell_height = 3
        start_y = (rows - cell_height * 8) // 2
        start_x = 20  # Start drawing the board from column 20 to make space for move history
        
        draw_board(stdscr, board, cell_width, cell_height, start_y, start_x, selected_square, move_history, legal_moves, player_color)
        
        if board.is_game_over():
            stdscr.addstr(rows - 1, 0, "Game Over! Press any key to exit.")
            stdscr.getch()
            break
        
        player_turn = board.turn == player_color
        
        while player_turn:
            try:
                key = stdscr.getch()
                
                if key == ord('q'):
                    engine.quit()
                    return
                
                if key == ord('u'):  # Undo both your move and the computer's move
                    if len(board.move_stack) > 1:
                        move1 = board.pop()
                        move2 = board.pop()
                        undo_stack.append((move1, move2))
                        redo_stack.clear()  # Clear redo stack as we made a new undo
                        move_history.pop()
                        move_history.pop()
                        draw_board(stdscr, board, cell_width, cell_height, start_y, start_x, selected_square, move_history, legal_moves, player_color)
                        break
                
                if key == ord('r'):  # Redo both your move and the computer's move
                    if len(undo_stack) > 0:
                        move1, move2 = undo_stack.pop()
                        board.push(move2)  # Push computer's move first
                        board.push(move1)  # Push your move
                        redo_stack.append((move1, move2))
                        move_history.append(f"{'White' if player_color == chess.WHITE else 'Black'}: {move1}")
                        move_history.append(f"{'Black' if player_color == chess.WHITE else 'White'}: {move2}")
                        draw_board(stdscr, board, cell_width, cell_height, start_y, start_x, selected_square, move_history, legal_moves, player_color)
                        break
                
                if key == curses.KEY_MOUSE:
                    _, mouse_x, mouse_y, _, button_state = curses.getmouse()
                    
                    if button_state & curses.BUTTON1_CLICKED:
                        square = get_square_from_position(mouse_x, mouse_y, cell_width, cell_height, start_x, start_y, player_color)
                        if square is not None:
                            if not piece_selected and board.piece_at(square) and board.piece_at(square).color == player_color:
                                selected_square = square
                                original_square = selected_square
                                piece_selected = True
                                moving_mode = False
                                legal_moves = [move.to_square for move in board.legal_moves if move.from_square == selected_square]
                                draw_board(stdscr, board, cell_width, cell_height, start_y, start_x, selected_square, move_history, legal_moves, player_color)
                            elif piece_selected and selected_square != square:
                                move = chess.Move(selected_square, square)
                                if move in board.legal_moves:
                                    board.push(move)
                                    move_history.append(f"{player_side}: {move}")
                                    selected_square = None
                                    piece_selected = False
                                    redo_stack.clear()  # Clear redo stack when a new move is made
                                    player_turn = False
                                    break
                                selected_square = None
                                piece_selected = False
                
                elif piece_selected:
                    if key in [curses.KEY_UP, curses.KEY_DOWN, curses.KEY_LEFT, curses.KEY_RIGHT]:
                        rank = chess.square_rank(selected_square)
                        file = chess.square_file(selected_square)
                        
                        if key == curses.KEY_UP:
                            rank += 1 if player_color == chess.WHITE else -1
                        elif key == curses.KEY_DOWN:
                            rank -= 1 if player_color == chess.WHITE else 1
                        elif key == curses.KEY_LEFT:
                            file -= 1 if player_color == chess.WHITE else -1
                        elif key == curses.KEY_RIGHT:
                            file += 1 if player_color == chess.WHITE else -1
                        
                        if 0 <= rank < 8 and 0 <= file < 8:
                            selected_square = chess.square(file, rank)
                            draw_board(stdscr, board, cell_width, cell_height, start_y, start_x, selected_square, move_history, legal_moves, player_color)
                    
                    elif key == ord('\n'):
                        if not moving_mode:
                            moving_mode = True
                            legal_moves = [move.to_square for move in board.legal_moves if move.from_square == selected_square]
                            original_square = selected_square
                            draw_board(stdscr, board, cell_width, cell_height, start_y, start_x, selected_square, move_history, legal_moves, player_color)
                        else:
                            if selected_square != original_square:
                                move = chess.Move(original_square, selected_square)
                                if move in board.legal_moves:
                                    board.push(move)
                                    move_history.append(f"{player_side}: {move}")
                                    selected_square = None
                                    piece_selected = False
                                    moving_mode = False
                                    redo_stack.clear()  # Clear the redo stack when a new move is made
                                    player_turn = False
                                    break
                            selected_square = original_square
                            moving_mode = False
                
            except curses.error:
                pass
        
        if not player_turn:
            result = engine.play(board, chess.engine.Limit(time=1.0 + (difficulty - 1) * 0.1))
            board.push(result.move)
            move_history.append(f"{'White' if not player_color else 'Black'}: {result.move}")
            undo_stack.clear()  # Clear undo stack after computer move
    
    engine.quit()

if __name__ == "__main__":
    curses.wrapper(main)

