import Foundation
import PokerCore
import PokerAI
import PokerCoach
import PokerSession
import PokerTests

/// Sits a scripted player down for a whole assessment and prints what it concluded.
///
/// The same reason `pokerlab coach` exists: a measurement nobody can run and read for themselves
/// is a claim. This one is worth running against `--player control` as well as against a planted
/// flaw, because a coach that finds something in a player with nothing wrong is the failure that
/// matters most.
///     pokerlab assess --format cash --setup deep --hands 200
///
/// `--setup` pins every hand to one arrangement and prints how often each situation came up, which
/// is where a setup's `expected` priors come from.
func runAssessment(playerName: String, seed: UInt64, hands: Int, setupID: String? = nil,
                   cash: CashSetup? = nil) {
    let player = plantedPlayer(named: playerName)
    // The catalogue edition — and so the list of setups — follows the structure before anything
    // is looked up.
    if let cash { LeakCatalogue.format = cash.structure == .fixedLimit ? .limit : .cash }
    if let setupID {
        guard let setup = AssessmentPlanner.setup(id: setupID) else { return print("no setup \(setupID)") }
        let session = playAssessment(player, seed: seed, hands: hands, pinned: setup, setup: cash)
        let played = session.history.hands
        print("Setup \(setup.id): \(played.count) hands, seed \(seed).  How often each situation came up per hand:")
        var counts: [SpotKind: Int] = [:]
        for hand in played {
            for verdict in hand.verdicts {
                if let spot = SpotKind.recorded(verdict.spot) { counts[spot, default: 0] += 1 }
            }
        }
        for spot in SpotKind.measured {
            let rate = Double(counts[spot] ?? 0) / Double(max(1, played.count))
            if rate > 0 { print(String(format: "  .%@: %.2f", "\(spot)", rate)) }
        }
        return
    }
    let session = playAssessment(player, seed: seed, hands: hands, setup: cash)
    guard let report = session.assessmentReport else { return print("no report") }

    print("Player: \(player.name).  \(report.hands) hands, seed \(seed).")
    print("")
    print(wrapped(report.headline))
    print("")
    print(wrapped(report.ratingLine))
    print("")

    if report.named.isEmpty, report.watching.isEmpty {
        print("Nothing named.")
    }
    for finding in report.named {
        print("  NAMED    \(finding.leak.name)")
        print("           \(finding.line)")
    }
    for finding in report.watching {
        print("  WATCHING \(finding.leak.name)")
        print("           \(finding.line)")
    }

    print("")
    print("What it got to look at")
    for area in report.areas {
        let name = area.name.padding(toLength: 34, withPad: " ", startingAt: 0)
        print(String(format: "  %@ %2d/%2d  sure %3.0f%%",
                     name, area.mistakes, area.chances, area.certainty * 100))
    }

    print("")
    print("What it arranged")
    for steer in report.steering {
        print("  \(steer.line)")
    }
}

private func wrapped(_ text: String, width: Int = 88) -> String {
    var lines: [String] = []
    var current = ""
    for word in text.split(separator: " ") {
        if current.count + word.count + 1 > width {
            lines.append(current)
            current = String(word)
        } else {
            current += current.isEmpty ? String(word) : " \(word)"
        }
    }
    if !current.isEmpty { lines.append(current) }
    return lines.joined(separator: "\n")
}
