"""
Piece Activity Analysis Tool
Evaluates piece mobility, centralization, and development.

Returns structured analysis of:
- Piece mobility (number of legal moves)
- Piece centralization (control of center squares)
- Development status (pieces developed vs on starting squares)
- Piece coordination and positioning quality
"""

import chess
from typing import Dict, List, Set


# Center squares (e4, d4, e5, d5)
CENTER_SQUARES = {chess.E4, chess.D4, chess.E5, chess.D5}

# Extended center (c3-f3-f6-c6 square)
EXTENDED_CENTER = {
    chess.C3, chess.D3, chess.E3, chess.F3,
    chess.C4, chess.D4, chess.E4, chess.F4,
    chess.C5, chess.D5, chess.E5, chess.F5,
    chess.C6, chess.D6, chess.E6, chess.F6
}

# Starting squares for pieces (used to check development)
WHITE_STARTING_SQUARES = {
    chess.B1, chess.G1,  # Knights
    chess.C1, chess.F1,  # Bishops
    chess.A1, chess.H1,  # Rooks
    chess.D1,  # Queen
}

BLACK_STARTING_SQUARES = {
    chess.B8, chess.G8,  # Knights
    chess.C8, chess.F8,  # Bishops
    chess.A8, chess.H8,  # Rooks
    chess.D8,  # Queen
}


def analyze_piece_activity(fen: str) -> Dict:
    """
    Analyze piece activity and mobility for a position.
    
    Args:
        fen: Position in FEN notation
    
    Returns:
        Dictionary with:
            - score: Activity score differential (positive = white more active)
            - factors: List of contributing factors (mobility, centralization, development)
            - evidence: Human-readable explanations
            - details: Detailed breakdown by side
    
    Example:
        >>> result = analyze_piece_activity("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1")
        >>> result['evidence']
        ['White has developed 1 piece', 'White controls the center with e4', ...]
    """
    board = chess.Board(fen)
    
    # Analyze both sides
    white_activity = _analyze_side_activity(board, chess.WHITE)
    black_activity = _analyze_side_activity(board, chess.BLACK)
    
    # Calculate activity differential
    score = white_activity['score'] - black_activity['score']
    
    factors = []
    evidence = []
    
    # Mobility comparison
    white_mobility = white_activity['mobility']
    black_mobility = black_activity['mobility']
    mobility_diff = white_mobility - black_mobility
    
    if mobility_diff > 5:
        factors.append({
            'type': 'mobility_advantage',
            'side': 'white',
            'value': mobility_diff
        })
        evidence.append(f"White has superior mobility ({white_mobility} vs {black_mobility} legal moves)")
    elif mobility_diff < -5:
        factors.append({
            'type': 'mobility_advantage',
            'side': 'black',
            'value': abs(mobility_diff)
        })
        evidence.append(f"Black has superior mobility ({black_mobility} vs {white_mobility} legal moves)")
    else:
        evidence.append(f"Mobility is roughly equal ({white_mobility} vs {black_mobility} legal moves)")
    
    # Center control comparison
    white_center = white_activity['center_control']
    black_center = black_activity['center_control']
    
    if white_center > black_center:
        factors.append({
            'type': 'center_control',
            'side': 'white',
            'squares': white_center
        })
        evidence.append(f"White controls more center squares ({white_center} vs {black_center})")
    elif black_center > white_center:
        factors.append({
            'type': 'center_control',
            'side': 'black',
            'squares': black_center
        })
        evidence.append(f"Black controls more center squares ({black_center} vs {white_center})")
    
    # Development comparison
    white_dev = white_activity['developed_pieces']
    black_dev = black_activity['developed_pieces']
    
    if white_dev > black_dev:
        factors.append({
            'type': 'development_advantage',
            'side': 'white',
            'pieces': white_dev
        })
        evidence.append(f"White is ahead in development ({white_dev} vs {black_dev} pieces developed)")
    elif black_dev > white_dev:
        factors.append({
            'type': 'development_advantage',
            'side': 'black',
            'pieces': black_dev
        })
        evidence.append(f"Black is ahead in development ({black_dev} vs {white_dev} pieces developed)")
    
    # Piece-specific observations
    _add_piece_observations(board, white_activity, black_activity, evidence)
    
    return {
        'score': score,
        'factors': factors,
        'evidence': evidence,
        'details': {
            'white': white_activity,
            'black': black_activity
        }
    }


def _analyze_side_activity(board: chess.Board, color: chess.Color) -> Dict:
    """
    Analyze activity for one side.
    
    Args:
        board: Chess board
        color: Color to analyze
    
    Returns:
        Dictionary with activity metrics
    """
    # Count legal moves (mobility)
    if board.turn == color:
        mobility = board.legal_moves.count()
    else:
        # Switch turn temporarily to count opponent's moves
        board_copy = board.copy()
        board_copy.turn = color
        mobility = board_copy.legal_moves.count()
    
    # Count developed pieces (not on starting squares)
    starting_squares = WHITE_STARTING_SQUARES if color == chess.WHITE else BLACK_STARTING_SQUARES
    developed_pieces = 0
    
    for piece_type in [chess.KNIGHT, chess.BISHOP, chess.ROOK, chess.QUEEN]:
        for square in board.pieces(piece_type, color):
            if square not in starting_squares:
                developed_pieces += 1
    
    # Count center control (pieces attacking center squares)
    center_control = 0
    extended_center_control = 0
    
    for square in CENTER_SQUARES:
        if board.is_attacked_by(color, square):
            center_control += 1
    
    for square in EXTENDED_CENTER:
        if board.is_attacked_by(color, square):
            extended_center_control += 1
    
    # Calculate activity score
    # Mobility: 1 point per 2 moves
    # Center control: 10 points per center square
    # Extended center: 3 points per square
    # Development: 15 points per developed piece
    score = (
        mobility // 2 +
        center_control * 10 +
        extended_center_control * 3 +
        developed_pieces * 15
    )
    
    return {
        'mobility': mobility,
        'developed_pieces': developed_pieces,
        'center_control': center_control,
        'extended_center_control': extended_center_control,
        'score': score
    }


def _add_piece_observations(board: chess.Board, white_activity: Dict, black_activity: Dict, evidence: List[str]):
    """
    Add specific observations about piece positioning.
    
    Args:
        board: Chess board
        white_activity: White's activity metrics
        black_activity: Black's activity metrics
        evidence: List to append observations to
    """
    # Check for knights on the rim
    for color, color_name in [(chess.WHITE, "White"), (chess.BLACK, "Black")]:
        knights = board.pieces(chess.KNIGHT, color)
        rim_squares = {
            chess.A1, chess.A2, chess.A3, chess.A4, chess.A5, chess.A6, chess.A7, chess.A8,
            chess.H1, chess.H2, chess.H3, chess.H4, chess.H5, chess.H6, chess.H7, chess.H8,
            chess.B1, chess.C1, chess.D1, chess.E1, chess.F1, chess.G1,
            chess.B8, chess.C8, chess.D8, chess.E8, chess.F8, chess.G8
        }
        
        for knight_sq in knights:
            if knight_sq in rim_squares and knight_sq not in {chess.B1, chess.G1, chess.B8, chess.G8}:
                evidence.append(f"{color_name} knight on {chess.square_name(knight_sq)} is poorly placed (rim)")
    
    # Check for centralized knights
    for color, color_name in [(chess.WHITE, "White"), (chess.BLACK, "Black")]:
        knights = board.pieces(chess.KNIGHT, color)
        good_knight_squares = {chess.D4, chess.E4, chess.D5, chess.E5, chess.C5, chess.F5, chess.C4, chess.F4}
        
        for knight_sq in knights:
            if knight_sq in good_knight_squares:
                evidence.append(f"{color_name} knight on {chess.square_name(knight_sq)} is well-centralized")
    
    # Check for bishop pair
    white_bishops = len(board.pieces(chess.BISHOP, chess.WHITE))
    black_bishops = len(board.pieces(chess.BISHOP, chess.BLACK))
    
    if white_bishops == 2 and black_bishops < 2:
        evidence.append("White has the bishop pair advantage")
    elif black_bishops == 2 and white_bishops < 2:
        evidence.append("Black has the bishop pair advantage")
    
    # Check for rook activity (on open/semi-open files)
    _check_rook_activity(board, evidence)


def _check_rook_activity(board: chess.Board, evidence: List[str]):
    """
    Check if rooks are on open or semi-open files.
    
    Args:
        board: Chess board
        evidence: List to append observations to
    """
    for file_idx in range(8):  # a-h files
        white_pawns = 0
        black_pawns = 0
        white_rooks = 0
        black_rooks = 0
        
        for rank in range(8):
            square = chess.square(file_idx, rank)
            piece = board.piece_at(square)
            
            if piece:
                if piece.piece_type == chess.PAWN:
                    if piece.color == chess.WHITE:
                        white_pawns += 1
                    else:
                        black_pawns += 1
                elif piece.piece_type == chess.ROOK:
                    if piece.color == chess.WHITE:
                        white_rooks += 1
                    else:
                        black_rooks += 1
        
        file_name = chr(ord('a') + file_idx)
        
        # Open file (no pawns)
        if white_pawns == 0 and black_pawns == 0:
            if white_rooks > 0:
                evidence.append(f"White rook on open {file_name}-file")
            if black_rooks > 0:
                evidence.append(f"Black rook on open {file_name}-file")
        
        # Semi-open file
        elif white_pawns == 0 and white_rooks > 0:
            evidence.append(f"White rook on semi-open {file_name}-file")
        elif black_pawns == 0 and black_rooks > 0:
            evidence.append(f"Black rook on semi-open {file_name}-file")
