import Foundation

/// USI（Universal Shogi Interface）プロトコルハンドラー
class USIProtocolHandler {
    
    // MARK: - Response Parsing
    
    /// USIレスポンスをパース
    static func parseResponse(_ line: String) -> USIResponse {
        let components = line.split(separator: " ", omittingEmptySubsequences: true)
        guard let firstToken = components.first else {
            return .unknown(line)
        }
        
        switch String(firstToken) {
        case "usiok":
            return .usiok
            
        case "readyok":
            return .readyok
            
        case "bestmove":
            let bestMove = components.count > 1 ? String(components[1]) : ""
            let ponder = components.count > 3 && components[2] == "ponder" ? String(components[3]) : nil
            return .bestmove(bestMove, ponder: ponder)
            
        case "info":
            return parseInfoResponse(components: Array(components.dropFirst()))
            
        case "option":
            return .option(line)
            
        default:
            return .unknown(line)
        }
    }
    
    /// infoレスポンスをパース
    private static func parseInfoResponse(components: [Substring]) -> USIResponse {
        var depth: Int?
        var score: Int?
        var scoreType: ScoreType = .cp
        var pv: [String] = []
        var multiPV: Int?
        
        var i = 0
        while i < components.count {
            let token = String(components[i])
            
            switch token {
            case "depth":
                if i + 1 < components.count {
                    depth = Int(components[i + 1])
                    i += 2
                } else {
                    i += 1
                }
                
            case "score":
                if i + 2 < components.count {
                    let scoreTypeStr = String(components[i + 1])
                    scoreType = scoreTypeStr == "mate" ? .mate : .cp
                    score = Int(components[i + 2])
                    i += 3
                } else {
                    i += 1
                }
                
            case "pv":
                // PV（主要変化）は残りの全トークン
                pv = components[(i + 1)...].map { String($0) }
                i = components.count
                
            case "multipv":
                if i + 1 < components.count {
                    multiPV = Int(components[i + 1])
                    i += 2
                } else {
                    i += 1
                }
                
            default:
                i += 1
            }
        }
        
        return .info(
            depth: depth,
            score: score,
            scoreType: scoreType,
            pv: pv,
            multiPV: multiPV
        )
    }
    
    // MARK: - Command Building
    
    /// usiコマンドを生成
    static func usiCommand() -> String {
        return "usi"
    }
    
    /// isreadyコマンドを生成
    static func isReadyCommand() -> String {
        return "isready"
    }
    
    /// setoptionコマンドを生成
    static func setOptionCommand(name: String, value: String) -> String {
        return "setoption name \(name) value \(value)"
    }
    
    /// positionコマンドを生成
    static func positionCommand(sfen: String, moves: [String] = []) -> String {
        var command = "position sfen \(sfen)"
        if !moves.isEmpty {
            command += " moves " + moves.joined(separator: " ")
        }
        return command
    }
    
    /// goコマンドを生成（時間制限）
    static func goCommand(moveTime: Int) -> String {
        return "go movetime \(moveTime)"
    }
    
    /// stopコマンドを生成
    static func stopCommand() -> String {
        return "stop"
    }
    
    /// quitコマンドを生成
    static func quitCommand() -> String {
        return "quit"
    }
}

// MARK: - USI Response Types

enum USIResponse {
    case usiok
    case readyok
    case bestmove(String, ponder: String?)
    case info(depth: Int?, score: Int?, scoreType: ScoreType, pv: [String], multiPV: Int?)
    case option(String)
    case unknown(String)
}

enum ScoreType {
    case cp  // センチポーン
    case mate  // 詰み
}
