import Foundation

/// Represents a chess piece color
enum PieceColor: String {
    case white
    case black
}

/// Represents a chess piece type
enum PieceType: String {
    case pawn
    case knight
    case bishop
    case rook
    case queen
    case king
    
    /// FEN notation for the piece
    var fenSymbol: String {
        switch self {
        case .pawn: return "p"
        case .knight: return "n"
        case .bishop: return "b"
        case .rook: return "r"
        case .queen: return "q"
        case .king: return "k"
        }
    }
}

/// Represents a chess piece with its type and color
struct ChessPiece: Equatable {
    let type: PieceType
    let color: PieceColor
    
    /// FEN notation for the piece (uppercase for white, lowercase for black)
    var fenSymbol: String {
        let symbol = type.fenSymbol
        return color == .white ? symbol.uppercased() : symbol
    }
}

/// Represents a position on the chess board
struct BoardPosition: Equatable {
    let file: Int // 0-7 for a-h
    let rank: Int // 0-7 for 1-8
    
    /// Initialize from algebraic notation (e.g., "e4")
    init?(algebraic: String) {
        guard algebraic.count == 2,
              let file = algebraic.first?.asciiValue,
              let rank = algebraic.last?.wholeNumberValue,
              file >= UInt8(ascii: "a"), file <= UInt8(ascii: "h"),
              rank >= 1, rank <= 8 else {
            return nil
        }
        
        self.file = Int(file - UInt8(ascii: "a"))
        self.rank = rank - 1
    }
    
    /// Convert to algebraic notation
    var algebraic: String {
        let fileChar = Character(UnicodeScalar(UInt8(ascii: "a") + UInt8(file)))
        return "\(fileChar)\(rank + 1)"
    }
    
    /// Validate if the position is within bounds
    var isValid: Bool {
        file >= 0 && file < 8 && rank >= 0 && rank < 8
    }
}

/// Represents a complete chess position
struct ChessPosition {
    /// 8x8 grid representing the board state, nil means empty square
    private var board: [[ChessPiece?]]
    
    /// Initialize an empty board
    init() {
        board = Array(repeating: Array(repeating: nil, count: 8), count: 8)
    }
    
    /// Initialize from FEN string
    init?(fen: String) {
        self.init()
        
        let components = fen.components(separatedBy: " ")
        guard components.count >= 1 else { return nil }
        
        let ranks = components[0].components(separatedBy: "/")
        guard ranks.count == 8 else { return nil }
        
        for (rankIndex, rank) in ranks.enumerated() {
            var fileIndex = 0
            
            for char in rank {
                if let number = Int(String(char)) {
                    fileIndex += number
                } else {
                    guard fileIndex < 8 else { return nil }
                    
                    let color: PieceColor = char.isUppercase ? .white : .black
                    let lowerChar = char.lowercased()
                    
                    guard let type = pieceTypeFromFen(String(lowerChar)) else { return nil }
                    
                    board[7 - rankIndex][fileIndex] = ChessPiece(type: type, color: color)
                    fileIndex += 1
                }
            }
            
            guard fileIndex == 8 else { return nil }
        }
    }
    
    /// Convert position to FEN string (piece placement only)
    var fen: String {
        var result = ""
        
        for rankIndex in (0...7).reversed() {
            var emptyCount = 0
            
            for fileIndex in 0...7 {
                if let piece = board[rankIndex][fileIndex] {
                    if emptyCount > 0 {
                        result += String(emptyCount)
                        emptyCount = 0
                    }
                    result += piece.fenSymbol
                } else {
                    emptyCount += 1
                }
            }
            
            if emptyCount > 0 {
                result += String(emptyCount)
            }
            
            if rankIndex > 0 {
                result += "/"
            }
        }
        
        return result
    }
    
    /// Get piece at position
    subscript(position: BoardPosition) -> ChessPiece? {
        get {
            guard position.isValid else { return nil }
            return board[position.rank][position.file]
        }
        set {
            guard position.isValid else { return }
            board[position.rank][position.file] = newValue
        }
    }
    
    /// Get piece at algebraic position
    subscript(algebraic: String) -> ChessPiece? {
        get {
            guard let position = BoardPosition(algebraic: algebraic) else { return nil }
            return self[position]
        }
        set {
            guard let position = BoardPosition(algebraic: algebraic) else { return }
            self[position] = newValue
        }
    }
    
    /// Validate if the position is legal
    var isValid: Bool {
        print("\n=== VALIDATING CHESS POSITION ===")
        var whitePieces = [PieceType: Int]()
        var blackPieces = [PieceType: Int]()
        
        // Count all pieces
        for rank in 0...7 {
            for file in 0...7 {
                if let piece = board[rank][file] {
                    if piece.color == .white {
                        whitePieces[piece.type, default: 0] += 1
                    } else {
                        blackPieces[piece.type, default: 0] += 1
                    }
                    
                    // Check pawns on invalid ranks
                    if piece.type == .pawn && (rank == 0 || rank == 7) {
                        print("ERROR: Pawn found on first/last rank")
                        return false
                    }
                }
            }
        }
        
        // Print piece counts
        print("White pieces:")
        for (type, count) in whitePieces {
            print("- \(type): \(count)")
        }
        print("Black pieces:")
        for (type, count) in blackPieces {
            print("- \(type): \(count)")
        }
        
        // Validate piece counts
        let whiteTotal = whitePieces.values.reduce(0, +)
        let blackTotal = blackPieces.values.reduce(0, +)
        
        if whiteTotal > 16 {
            print("ERROR: Too many white pieces (\(whiteTotal))")
            return false
        }
        if blackTotal > 16 {
            print("ERROR: Too many black pieces (\(blackTotal))")
            return false
        }
        
        // Validate kings
        if whitePieces[.king] ?? 0 != 1 {
            print("ERROR: Invalid number of white kings (\(whitePieces[.king] ?? 0))")
            return false
        }
        if blackPieces[.king] ?? 0 != 1 {
            print("ERROR: Invalid number of black kings (\(blackPieces[.king] ?? 0))")
            return false
        }
        
        // Validate pawns
        if whitePieces[.pawn] ?? 0 > 8 {
            print("ERROR: Too many white pawns (\(whitePieces[.pawn] ?? 0))")
            return false
        }
        if blackPieces[.pawn] ?? 0 > 8 {
            print("ERROR: Too many black pawns (\(blackPieces[.pawn] ?? 0))")
            return false
        }
        
        // Validate other pieces
        for pieceType in [PieceType.queen, .rook, .bishop, .knight] {
            if whitePieces[pieceType] ?? 0 > 2 {
                print("ERROR: Too many white \(pieceType)s (\(whitePieces[pieceType] ?? 0))")
                return false
            }
            if blackPieces[pieceType] ?? 0 > 2 {
                print("ERROR: Too many black \(pieceType)s (\(blackPieces[pieceType] ?? 0))")
                return false
            }
        }
        
        print("Position validation successful")
        return true
    }
    
    /// Helper function to convert FEN piece symbol to PieceType
    private func pieceTypeFromFen(_ symbol: String) -> PieceType? {
        switch symbol {
        case "p": return .pawn
        case "n": return .knight
        case "b": return .bishop
        case "r": return .rook
        case "q": return .queen
        case "k": return .king
        default: return nil
        }
    }
    
    /// Initialize with the standard starting position
    static var startingPosition: ChessPosition {
        // swiftlint:disable:next force_unwrapping
        ChessPosition(fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR")!
    }
}
