import AppKit
import ApplicationServices
import Foundation

struct WindowState: Codable {
    let windowID: Int64?
    let x: Double
    let y: Double
    let width: Double
    let height: Double
    let minimized: Bool
    let source: Bool
}

struct RestoreSummary {
    let mutableRecorded: Int
    let restored: Int
    let mutationFailures: Int

    var exitCode: Int32 {
        restored == mutableRecorded && mutationFailures == 0 ? 0 : 75
    }
}

enum AXReadFailure: Error {
    case nonBenign(AXError)
    case traversalLimit
}

enum BindingPlanFailure: Error {
    case invalidSource
    case duplicateNonSourceID
    case missingNonSource
    case readError
}

struct WindowBindingPlan {
    let states: [WindowState]
    let windowIndices: [Int]
}

enum IsolationFailureStage: String, Equatable {
    case otherWindowMinimizeSetFailed = "OTHER_WINDOW_MINIMIZE_SET_FAILED"
    case sourceUnminimizeSetFailed = "SOURCE_UNMINIMIZE_SET_FAILED"
    case sourceSizeSetFailed = "SOURCE_SIZE_SET_FAILED"
    case sourcePositionSetFailed = "SOURCE_POSITION_SET_FAILED"
    case sourceRaiseFailed = "SOURCE_RAISE_FAILED"
    case sourceReadbackAXFailed = "SOURCE_READBACK_AX_FAILED"
    case sourceReadbackMismatch = "SOURCE_READBACK_MISMATCH"
}

enum PreStateFailureStage: String, Equatable {
    case finderNotRunning = "FINDER_NOT_RUNNING"
    case finderWindowsReadFailed = "FINDER_WINDOWS_READ_FAILED"
    case stateEncodeFailed = "STATE_ENCODE_FAILED"
    case stateAtomicWriteFailed = "STATE_ATOMIC_WRITE_FAILED"
}

enum StatePersistenceFailure: Error, Equatable {
    case encode
    case atomicWrite

    var stage: PreStateFailureStage {
        switch self {
        case .encode: return .stateEncodeFailed
        case .atomicWrite: return .stateAtomicWriteFailed
        }
    }
}

enum IsolationMutationResult: Equatable {
    case success
    case failure(IsolationFailureStage)
}

struct IsolationFailureResult {
    let line: String
    let exitCode: Int32
}

func preStateFailureLine(_ stage: PreStateFailureStage) -> String {
    "stage=\(stage.rawValue) mutation=0"
}

func persistStateSnapshot(
    encode: () throws -> Data,
    atomicWrite: (Data) throws -> Void
) -> Result<Void, StatePersistenceFailure> {
    let data: Data
    do { data = try encode() } catch { return .failure(.encode) }
    do { try atomicWrite(data) } catch { return .failure(.atomicWrite) }
    return .success(())
}

func isBenignAbsence(_ error: AXError) -> Bool {
    error == .noValue || error == .attributeUnsupported
}

func uniqueSourceWindow(_ result: Result<[Int], AXReadFailure>) throws -> Int? {
    let perWindowMatchCounts = try result.get()
    guard perWindowMatchCounts.reduce(0, +) == 1 else { return nil }
    return perWindowMatchCounts.firstIndex(of: 1)
}

func buildIsolationPlan(
    sourceIndex: Int,
    windowCount: Int,
    windowID: (Int) -> Result<Int64?, AXReadFailure>,
    rect: (Int) -> Result<CGRect?, AXReadFailure>,
    minimized: (Int) -> Result<Bool?, AXReadFailure>
) -> Result<WindowBindingPlan, BindingPlanFailure> {
    guard (0..<windowCount).contains(sourceIndex) else { return .failure(.invalidSource) }
    let sourceRect: CGRect
    switch rect(sourceIndex) {
    case .failure: return .failure(.readError)
    case .success(let value):
        guard let value, validRect(value) else { return .failure(.invalidSource) }
        sourceRect = value
    }
    let sourceMinimized: Bool
    switch minimized(sourceIndex) {
    case .failure: return .failure(.readError)
    case .success(let value):
        guard let value else { return .failure(.invalidSource) }
        sourceMinimized = value
    }
    var states = [WindowState(
        windowID: nil,
        x: sourceRect.origin.x,
        y: sourceRect.origin.y,
        width: sourceRect.width,
        height: sourceRect.height,
        minimized: sourceMinimized,
        source: true
    )]
    var indices = [sourceIndex]
    var usedIDs: Set<Int64> = []
    for index in 0..<windowCount where index != sourceIndex {
        let id: Int64
        switch windowID(index) {
        case .failure: return .failure(.readError)
        case .success(nil): continue
        case .success(let value): id = value!
        }
        guard usedIDs.insert(id).inserted else { return .failure(.duplicateNonSourceID) }
        let windowRect: CGRect
        switch rect(index) {
        case .failure: return .failure(.readError)
        case .success(let value):
            guard let value, validRect(value) else { continue }
            windowRect = value
        }
        let windowMinimized: Bool
        switch minimized(index) {
        case .failure: return .failure(.readError)
        case .success(let value):
            guard let value else { continue }
            windowMinimized = value
        }
        states.append(WindowState(
            windowID: id,
            x: windowRect.origin.x,
            y: windowRect.origin.y,
            width: windowRect.width,
            height: windowRect.height,
            minimized: windowMinimized,
            source: false
        ))
        indices.append(index)
    }
    return .success(WindowBindingPlan(states: states, windowIndices: indices))
}

func buildRestorePlan(
    states: [WindowState],
    sourceIndex: Int?,
    windowCount: Int,
    windowID: (Int) -> Result<Int64?, AXReadFailure>,
    sourceRect: () -> Result<CGRect?, AXReadFailure>,
    sourceMinimized: () -> Result<Bool?, AXReadFailure>
) -> Result<WindowBindingPlan, BindingPlanFailure> {
    guard let sourceIndex, (0..<windowCount).contains(sourceIndex),
          states.filter(\.source).count == 1,
          let sourceState = states.first(where: \.source) else { return .failure(.invalidSource) }
    switch sourceRect() {
    case .failure: return .failure(.readError)
    case .success(let value): guard let value, validRect(value) else { return .failure(.invalidSource) }
    }
    switch sourceMinimized() {
    case .failure: return .failure(.readError)
    case .success(let value): guard value != nil else { return .failure(.invalidSource) }
    }
    var currentByID: [Int64: Int] = [:]
    for index in 0..<windowCount where index != sourceIndex {
        switch windowID(index) {
        case .failure: return .failure(.readError)
        case .success(nil): continue
        case .success(let value):
            let id = value!
            guard currentByID[id] == nil else { return .failure(.duplicateNonSourceID) }
            currentByID[id] = index
        }
    }
    var stateIDs: Set<Int64> = []
    var planStates = [sourceState]
    var indices = [sourceIndex]
    for state in states where !state.source {
        guard let id = state.windowID, stateIDs.insert(id).inserted,
              let index = currentByID[id] else { return .failure(.missingNonSource) }
        planStates.append(state)
        indices.append(index)
    }
    return .success(WindowBindingPlan(states: planStates, windowIndices: indices))
}

func restoreRecorded(
    _ plan: WindowBindingPlan,
    restore: (WindowState, Int) -> Bool
) -> Bool {
    zip(plan.states, plan.windowIndices).map(restore).allSatisfy { $0 }
}

func validRect(_ rect: CGRect?) -> Bool {
    guard let rect else { return false }
    return [rect.origin.x, rect.origin.y, rect.size.width, rect.size.height].allSatisfy(\.isFinite)
        && rect.size.width > 0 && rect.size.height > 0
}

func isIsolationReadbackCompatible(
    exactUniqueBound: Bool,
    minimized: Bool?,
    windowRect: CGRect?,
    displayBounds: [CGRect]
) -> Bool {
    guard exactUniqueBound, minimized == false,
          let windowRect, validRect(windowRect), !displayBounds.isEmpty,
          displayBounds.allSatisfy({ validRect($0) }) else { return false }
    let center = CGPoint(x: windowRect.midX, y: windowRect.midY)
    return displayBounds.contains(where: { $0.contains(center) })
}

func postMutationReadbackExit(
    _ readback: Result<Bool, AXReadFailure>,
    validationFailure: Int32,
    cleanupFailure: Int32,
    rollback: () -> Bool
) -> Int32? {
    if case .success(true) = readback { return nil }
    return rollback() ? validationFailure : cleanupFailure
}

func runIsolationMutationCore(
    otherWindowCount: Int,
    minimizeOther: (Int) -> Bool,
    unminimizeSource: () -> Bool,
    setSourceSize: () -> Bool,
    setSourcePosition: () -> Bool,
    raiseSource: () -> Bool,
    beforeReadback: () -> Void,
    readback: () -> Result<Bool, AXReadFailure>
) -> IsolationMutationResult {
    for index in 0..<otherWindowCount {
        guard minimizeOther(index) else { return .failure(.otherWindowMinimizeSetFailed) }
    }
    guard unminimizeSource() else { return .failure(.sourceUnminimizeSetFailed) }
    guard setSourceSize() else { return .failure(.sourceSizeSetFailed) }
    guard setSourcePosition() else { return .failure(.sourcePositionSetFailed) }
    guard raiseSource() else { return .failure(.sourceRaiseFailed) }
    beforeReadback()
    switch readback() {
    case .failure: return .failure(.sourceReadbackAXFailed)
    case .success(true): return .success
    case .success(false): return .failure(.sourceReadbackMismatch)
    }
}

func finishIsolationFailure(
    _ stage: IsolationFailureStage,
    rollback: () -> Bool
) -> IsolationFailureResult {
    let rollbackComplete = rollback()
    return IsolationFailureResult(
        line: "stage=\(stage.rawValue) rollback=\(rollbackComplete ? "PASS" : "FAIL")",
        exitCode: rollbackComplete ? 72 : 73
    )
}

func countExactSourceCore<Node>(
    _ node: Node,
    depth: Int = 0,
    depthLimit: Int,
    matches: (Node) throws -> Bool,
    children: (Node) throws -> [Node]
) throws -> Int {
    var count = try matches(node) ? 1 : 0
    let childNodes = try children(node)
    if depth == depthLimit {
        guard childNodes.isEmpty else { throw AXReadFailure.traversalLimit }
        return count
    }
    guard depth < depthLimit else { throw AXReadFailure.traversalLimit }
    for child in childNodes {
        count += try countExactSourceCore(
            child,
            depth: depth + 1,
            depthLimit: depthLimit,
            matches: matches,
            children: children
        )
    }
    return count
}

func selfTest() -> Int32 {
    enum StateFixtureError: Error { case expected }
    func isTraversalLimit(_ result: Result<Int, Error>) -> Bool {
        guard case .failure(let error) = result,
              let failure = error as? AXReadFailure else { return false }
        if case .traversalLimit = failure { return true }
        return false
    }
    struct TraversalNode {
        let matches: Bool
        let children: [Int]
    }
    let limit = 14
    var shallowNodes = [TraversalNode(matches: false, children: [1])]
    shallowNodes.append(TraversalNode(matches: true, children: []))
    let shallowUnique = try? countExactSourceCore(
        0,
        depthLimit: limit,
        matches: { shallowNodes[$0].matches },
        children: { shallowNodes[$0].children }
    )
    let boundaryLeafNodes = (0...limit).map { depth in
        TraversalNode(matches: depth == limit, children: depth == limit ? [] : [depth + 1])
    }
    let boundaryLeaf = try? countExactSourceCore(
        0,
        depthLimit: limit,
        matches: { boundaryLeafNodes[$0].matches },
        children: { boundaryLeafNodes[$0].children }
    )
    var truncatedNodes = boundaryLeafNodes
    truncatedNodes[limit] = TraversalNode(matches: false, children: [limit + 1])
    truncatedNodes.append(TraversalNode(matches: true, children: []))
    var truncatedReads = 0
    let truncatedResult = Result {
        try countExactSourceCore(
            0,
            depthLimit: limit,
            matches: { truncatedReads += 1; return truncatedNodes[$0].matches },
            children: { truncatedReads += 1; return truncatedNodes[$0].children }
        )
    }
    var hiddenDuplicateNodes = [TraversalNode(matches: false, children: [1, 2])]
    hiddenDuplicateNodes.append(TraversalNode(matches: true, children: []))
    let chainStart = hiddenDuplicateNodes.count
    for depth in 1...limit {
        hiddenDuplicateNodes.append(TraversalNode(matches: false, children: [chainStart + depth]))
    }
    hiddenDuplicateNodes.append(TraversalNode(matches: true, children: []))
    var hiddenDuplicateTerminalReads = 0
    let hiddenDuplicateResult = Result {
        try countExactSourceCore(
            0,
            depthLimit: limit,
            matches: { hiddenDuplicateTerminalReads += 1; return hiddenDuplicateNodes[$0].matches },
            children: { hiddenDuplicateTerminalReads += 1; return hiddenDuplicateNodes[$0].children }
        )
    }
    let expectedStageCases: [(String, IsolationFailureStage, [String])] = [
        ("other-1", .otherWindowMinimizeSetFailed, ["other-0", "other-1"]),
        ("unminimize", .sourceUnminimizeSetFailed, ["other-0", "other-1", "unminimize"]),
        ("size", .sourceSizeSetFailed, ["other-0", "other-1", "unminimize", "size"]),
        ("position", .sourcePositionSetFailed, ["other-0", "other-1", "unminimize", "size", "position"]),
        ("raise", .sourceRaiseFailed, ["other-0", "other-1", "unminimize", "size", "position", "raise"])
    ]
    var stageCasesPass = true
    for (failedOperation, expectedStage, expectedCalls) in expectedStageCases {
        var calls: [String] = []
        let result = runIsolationMutationCore(
            otherWindowCount: 2,
            minimizeOther: { index in calls.append("other-\(index)"); return "other-\(index)" != failedOperation },
            unminimizeSource: { calls.append("unminimize"); return failedOperation != "unminimize" },
            setSourceSize: { calls.append("size"); return failedOperation != "size" },
            setSourcePosition: { calls.append("position"); return failedOperation != "position" },
            raiseSource: { calls.append("raise"); return failedOperation != "raise" },
            beforeReadback: { calls.append("wait") },
            readback: { calls.append("readback"); return .success(true) }
        )
        stageCasesPass = stageCasesPass
            && result == .failure(expectedStage)
            && calls == expectedCalls
    }
    var readErrorCalls: [String] = []
    let readErrorStage = runIsolationMutationCore(
        otherWindowCount: 0,
        minimizeOther: { _ in readErrorCalls.append("other"); return true },
        unminimizeSource: { readErrorCalls.append("unminimize"); return true },
        setSourceSize: { readErrorCalls.append("size"); return true },
        setSourcePosition: { readErrorCalls.append("position"); return true },
        raiseSource: { readErrorCalls.append("raise"); return true },
        beforeReadback: { readErrorCalls.append("wait") },
        readback: { readErrorCalls.append("readback"); return .failure(.nonBenign(.cannotComplete)) }
    )
    var mismatchCalls: [String] = []
    let mismatchStage = runIsolationMutationCore(
        otherWindowCount: 0,
        minimizeOther: { _ in mismatchCalls.append("other"); return true },
        unminimizeSource: { mismatchCalls.append("unminimize"); return true },
        setSourceSize: { mismatchCalls.append("size"); return true },
        setSourcePosition: { mismatchCalls.append("position"); return true },
        raiseSource: { mismatchCalls.append("raise"); return true },
        beforeReadback: { mismatchCalls.append("wait") },
        readback: { mismatchCalls.append("readback"); return .success(false) }
    )
    var successCalls: [String] = []
    let successStage = runIsolationMutationCore(
        otherWindowCount: 1,
        minimizeOther: { index in successCalls.append("other-\(index)"); return true },
        unminimizeSource: { successCalls.append("unminimize"); return true },
        setSourceSize: { successCalls.append("size"); return true },
        setSourcePosition: { successCalls.append("position"); return true },
        raiseSource: { successCalls.append("raise"); return true },
        beforeReadback: { successCalls.append("wait") },
        readback: { successCalls.append("readback"); return .success(true) }
    )
    var rollbackPassCalls = 0
    let rollbackPass = finishIsolationFailure(.sourcePositionSetFailed) {
        rollbackPassCalls += 1
        return true
    }
    var rollbackFailCalls = 0
    let rollbackFail = finishIsolationFailure(.sourceReadbackAXFailed) {
        rollbackFailCalls += 1
        return false
    }
    let displayBounds = [CGRect(x: 0, y: 0, width: 1920, height: 1080)]
    let finderNormalizedRect = CGRect(x: 18, y: 62, width: 497, height: 325)
    let invalidReadbackRects: [CGRect?] = [
        nil,
        .zero,
        CGRect(x: 10, y: 70, width: 0, height: 320),
        CGRect(x: 10, y: 70, width: 500, height: -1),
        CGRect(x: CGFloat.nan, y: 70, width: 500, height: 320),
        CGRect(x: 10, y: CGFloat.infinity, width: 500, height: 320),
        CGRect(x: 2500, y: 70, width: 500, height: 320),
        CGRect(x: -499, y: 70, width: 500, height: 320),
    ]
    let normalizedReadbackAccepted = isIsolationReadbackCompatible(
        exactUniqueBound: true,
        minimized: false,
        windowRect: finderNormalizedRect,
        displayBounds: displayBounds
    )
    let tinyPositiveOnscreenAccepted = isIsolationReadbackCompatible(
        exactUniqueBound: true,
        minimized: false,
        windowRect: CGRect(x: 1, y: 1, width: 1, height: 1),
        displayBounds: displayBounds
    )
    let invalidReadbacksRejected = invalidReadbackRects.allSatisfy {
        !isIsolationReadbackCompatible(
            exactUniqueBound: true,
            minimized: false,
            windowRect: $0,
            displayBounds: displayBounds
        )
    }
    let invalidDisplayBounds = [
        CGRect.zero,
        CGRect(x: 0, y: 0, width: -1, height: 100),
        CGRect(x: CGFloat.nan, y: 0, width: 100, height: 100),
        CGRect(x: 0, y: CGFloat.infinity, width: 100, height: 100),
    ]
    let mixedInvalidDisplaysRejected = invalidDisplayBounds.allSatisfy { invalidDisplay in
        !isIsolationReadbackCompatible(
            exactUniqueBound: true,
            minimized: false,
            windowRect: finderNormalizedRect,
            displayBounds: [invalidDisplay, displayBounds[0]]
        )
    }
    let pureInvalidDisplaysRejected = invalidDisplayBounds.allSatisfy { invalidDisplay in
        !isIsolationReadbackCompatible(
            exactUniqueBound: true,
            minimized: false,
            windowRect: finderNormalizedRect,
            displayBounds: [invalidDisplay]
        )
    }
    let fourDirectionDisplays = [
        CGRect(x: -100, y: 0, width: 100, height: 100),
        CGRect(x: 0, y: 0, width: 100, height: 100),
        CGRect(x: 100, y: 0, width: 100, height: 100),
        CGRect(x: 0, y: -100, width: 100, height: 100),
        CGRect(x: 0, y: 100, width: 100, height: 100),
    ]
    let fourDirectionCentersAccepted = [
        CGPoint(x: -50, y: 50),
        CGPoint(x: 150, y: 50),
        CGPoint(x: 50, y: -50),
        CGPoint(x: 50, y: 150),
    ].allSatisfy { center in
        isIsolationReadbackCompatible(
            exactUniqueBound: true,
            minimized: false,
            windowRect: CGRect(x: center.x - 10, y: center.y - 10, width: 20, height: 20),
            displayBounds: fourDirectionDisplays
        )
    }
    let validDisplaysOffscreenRejected = !isIsolationReadbackCompatible(
        exactUniqueBound: true,
        minimized: false,
        windowRect: CGRect(x: 300, y: 300, width: 20, height: 20),
        displayBounds: fourDirectionDisplays
    )
    let sourceWithoutID = WindowState(
        windowID: nil,
        x: 10,
        y: 20,
        width: 500,
        height: 320,
        minimized: false,
        source: true
    )
    let goodRect = CGRect(x: 10, y: 20, width: 500, height: 320)
    var sourceIDReads = 0
    let isolationResult = buildIsolationPlan(
        sourceIndex: 1,
        windowCount: 3,
        windowID: { index in
            if index == 1 { sourceIDReads += 1; return .success(nil) }
            return index == 0 ? .success(10) : .success(nil)
        },
        rect: { _ in .success(goodRect) },
        minimized: { _ in .success(false) }
    )
    guard case .success(let isolationPlan) = isolationResult else { return 1 }
    let duplicateResult = buildIsolationPlan(
        sourceIndex: 1,
        windowCount: 3,
        windowID: { $0 == 1 ? .success(nil) : .success(10) },
        rect: { _ in .success(goodRect) },
        minimized: { _ in .success(false) }
    )
    let restoreResult = buildRestorePlan(
        states: isolationPlan.states,
        sourceIndex: 1,
        windowCount: 3,
        windowID: { $0 == 0 ? .success(10) : .success(nil) },
        sourceRect: { .success(goodRect) },
        sourceMinimized: { .success(false) }
    )
    guard case .success(let restorePlan) = restoreResult else { return 1 }
    var restoreCalls: [Int] = []
    let restoreComplete = restoreRecorded(restorePlan) { _, index in restoreCalls.append(index); return true }
    var failedRestoreCalls: [Int] = []
    let restoreIncomplete = restoreRecorded(restorePlan) { _, index in
        failedRestoreCalls.append(index)
        return index != 1
    }
    var terminalIDReads = 0
    let terminalResult = buildIsolationPlan(
        sourceIndex: 0,
        windowCount: 4,
        windowID: { index in
            terminalIDReads += 1
            if index == 1 || index == 2 { return .success(10) }
            return .success(11)
        },
        rect: { _ in .success(goodRect) },
        minimized: { _ in .success(false) }
    )
    var restoreTerminalIDReads = 0
    let restoreTerminalResult = buildRestorePlan(
        states: [sourceWithoutID],
        sourceIndex: 0,
        windowCount: 4,
        windowID: { index in
            restoreTerminalIDReads += 1
            if index == 1 || index == 2 { return .success(10) }
            return .success(11)
        },
        sourceRect: { .success(goodRect) },
        sourceMinimized: { .success(false) }
    )
    let traversalErrorRejected: Bool
    do {
        _ = try uniqueSourceWindow(.failure(.nonBenign(.cannotComplete)))
        traversalErrorRejected = false
    } catch {
        traversalErrorRejected = true
    }
    var rollbackCalled = 0
    let readErrorCleanupSuccess = postMutationReadbackExit(
        .failure(.nonBenign(.cannotComplete)), validationFailure: 72, cleanupFailure: 73
    ) { rollbackCalled += 1; return true }
    let readErrorCleanupFailure = postMutationReadbackExit(
        .failure(.nonBenign(.cannotComplete)), validationFailure: 72, cleanupFailure: 73
    ) { rollbackCalled += 1; return false }
    var persistedBytes = Data()
    let persistenceSuccess = persistStateSnapshot(
        encode: { Data("state".utf8) },
        atomicWrite: { persistedBytes = $0 }
    )
    let persistenceEncodeFailure = persistStateSnapshot(
        encode: { throw StateFixtureError.expected },
        atomicWrite: { _ in fatalError("write must not run after encode failure") }
    )
    let persistenceWriteFailure = persistStateSnapshot(
        encode: { Data("state".utf8) },
        atomicWrite: { _ in throw StateFixtureError.expected }
    )
    guard mixedInvalidDisplaysRejected,
          pureInvalidDisplaysRejected,
          fourDirectionCentersAccepted,
          validDisplaysOffscreenRejected,
          normalizedReadbackAccepted,
          tinyPositiveOnscreenAccepted,
          invalidReadbacksRejected,
          !isIsolationReadbackCompatible(exactUniqueBound: false, minimized: false, windowRect: finderNormalizedRect, displayBounds: displayBounds),
          !isIsolationReadbackCompatible(exactUniqueBound: true, minimized: nil, windowRect: finderNormalizedRect, displayBounds: displayBounds),
          !isIsolationReadbackCompatible(exactUniqueBound: true, minimized: true, windowRect: finderNormalizedRect, displayBounds: displayBounds),
          !isIsolationReadbackCompatible(exactUniqueBound: true, minimized: false, windowRect: finderNormalizedRect, displayBounds: []),
          stageCasesPass,
          readErrorStage == .failure(.sourceReadbackAXFailed),
          readErrorCalls == ["unminimize", "size", "position", "raise", "wait", "readback"],
          mismatchStage == .failure(.sourceReadbackMismatch),
          mismatchCalls == ["unminimize", "size", "position", "raise", "wait", "readback"],
          successStage == .success,
          successCalls == ["other-0", "unminimize", "size", "position", "raise", "wait", "readback"],
          rollbackPassCalls == 1,
          rollbackPass.exitCode == 72,
          rollbackPass.line == "stage=SOURCE_POSITION_SET_FAILED rollback=PASS",
          rollbackFailCalls == 1,
          rollbackFail.exitCode == 73,
          rollbackFail.line == "stage=SOURCE_READBACK_AX_FAILED rollback=FAIL",
          shallowUnique == 1,
          boundaryLeaf == 1,
          isTraversalLimit(truncatedResult),
          truncatedReads == 30,
          isTraversalLimit(hiddenDuplicateResult),
          hiddenDuplicateTerminalReads == 32,
          sourceWithoutID.windowID == nil,
          sourceIDReads == 0,
          isolationPlan.states.count == 2,
          isolationPlan.states[0].source,
          isolationPlan.states[0].windowID == nil,
          isolationPlan.windowIndices == [1, 0],
          isolationPlan.states[1].windowID == 10,
          { if case .failure(.duplicateNonSourceID) = duplicateResult { return true }; return false }(),
          restorePlan.windowIndices == [1, 0],
          restorePlan.states.map(\.source) == [true, false],
          restoreComplete, restoreCalls == [1, 0],
          !restoreIncomplete, failedRestoreCalls == [1, 0],
          { if case .failure(.duplicateNonSourceID) = terminalResult { return true }; return false }(),
          terminalIDReads == 2,
          { if case .failure(.duplicateNonSourceID) = restoreTerminalResult { return true }; return false }(),
          restoreTerminalIDReads == 2,
          try! uniqueSourceWindow(.success([0, 1, 0])) == 1,
          try! uniqueSourceWindow(.success([0, 0])) == nil,
          try! uniqueSourceWindow(.success([1, 1])) == nil,
          traversalErrorRejected,
          isBenignAbsence(.noValue), isBenignAbsence(.attributeUnsupported),
          !isBenignAbsence(.cannotComplete), !isBenignAbsence(.invalidUIElement), !isBenignAbsence(.apiDisabled),
          validRect(CGRect(x: 1, y: 2, width: 3, height: 4)),
          !validRect(.zero),
          RestoreSummary(mutableRecorded: 2, restored: 2, mutationFailures: 0).exitCode == 0,
          RestoreSummary(mutableRecorded: 2, restored: 1, mutationFailures: 0).exitCode != 0,
          RestoreSummary(mutableRecorded: 2, restored: 2, mutationFailures: 1).exitCode != 0,
          rollbackCalled == 2, readErrorCleanupSuccess == 72, readErrorCleanupFailure == 73,
          postMutationReadbackExit(.success(true), validationFailure: 72, cleanupFailure: 73, rollback: { false }) == nil,
          preStateFailureLine(.finderNotRunning) == "stage=FINDER_NOT_RUNNING mutation=0",
          preStateFailureLine(.finderWindowsReadFailed) == "stage=FINDER_WINDOWS_READ_FAILED mutation=0",
          { if case .success = persistenceSuccess { return true }; return false }(),
          persistedBytes == Data("state".utf8),
          { if case .failure(.encode) = persistenceEncodeFailure { return true }; return false }(),
          { if case .failure(.atomicWrite) = persistenceWriteFailure { return true }; return false }(),
          StatePersistenceFailure.encode.stage == .stateEncodeFailed,
          StatePersistenceFailure.atomicWrite.stage == .stateAtomicWriteFailed else { return 1 }
    print("self_test=PASS exact_unique_window=true traversal_read_error_rejected=true post_mutation_read_error_rollback=true cleanup_status_distinct=true pre_state_observability=true state_write_classification=true")
    return 0
}

if CommandLine.arguments == [CommandLine.arguments[0], "--self-test"] { exit(selfTest()) }
guard CommandLine.arguments.count == 4,
      ["isolate", "restore"].contains(CommandLine.arguments[1]),
      !CommandLine.arguments[2].isEmpty,
      !CommandLine.arguments[3].isEmpty else {
    fputs("usage: FinderWindowIsolation isolate|restore state.json exactSourceIdentifier\n", stderr)
    exit(64)
}
let mode = CommandLine.arguments[1]
let stateURL = URL(fileURLWithPath: CommandLine.arguments[2])
let exactSourceIdentifier = CommandLine.arguments[3]
let axWindowNumberAttribute = "AXWindowNumber"

func attr(_ element: AXUIElement, _ name: String) throws -> CFTypeRef? {
    var value: CFTypeRef?
    let error = AXUIElementCopyAttributeValue(element, name as CFString, &value)
    if error == .success { return value }
    if isBenignAbsence(error) { return nil }
    throw AXReadFailure.nonBenign(error)
}
func text(_ element: AXUIElement, _ name: String) throws -> String? {
    guard let value = try attr(element, name), CFGetTypeID(value) == CFStringGetTypeID() else { return nil }
    return value as? String
}
func bool(_ element: AXUIElement, _ name: String) throws -> Bool? {
    guard let value = try attr(element, name), CFGetTypeID(value) == CFBooleanGetTypeID() else { return nil }
    return CFBooleanGetValue((value as! CFBoolean))
}
func number(_ element: AXUIElement, _ name: String) throws -> Int64? {
    guard let value = try attr(element, name), CFGetTypeID(value) == CFNumberGetTypeID() else { return nil }
    var result: Int64 = 0
    return CFNumberGetValue((value as! CFNumber), .sInt64Type, &result) ? result : nil
}
func rect(_ element: AXUIElement) throws -> CGRect? {
    guard let pv = try attr(element, kAXPositionAttribute), CFGetTypeID(pv) == AXValueGetTypeID(),
          let sv = try attr(element, kAXSizeAttribute), CFGetTypeID(sv) == AXValueGetTypeID() else { return nil }
    var point = CGPoint.zero
    var size = CGSize.zero
    guard AXValueGetValue(pv as! AXValue, .cgPoint, &point),
          AXValueGetValue(sv as! AXValue, .cgSize, &size) else { return nil }
    return CGRect(origin: point, size: size)
}
func activeDisplayBounds() -> [CGRect]? {
    var count: UInt32 = 0
    guard CGGetActiveDisplayList(0, nil, &count) == .success, count > 0 else { return nil }
    var identifiers = [CGDirectDisplayID](repeating: 0, count: Int(count))
    guard CGGetActiveDisplayList(count, &identifiers, &count) == .success else { return nil }
    return identifiers.prefix(Int(count)).map(CGDisplayBounds)
}
func countExactSource(_ element: AXUIElement, depth: Int = 0) throws -> Int {
    try countExactSourceCore(
        element,
        depth: depth,
        depthLimit: 14,
        matches: {
            try text($0, kAXRoleAttribute) == (kAXTextFieldRole as String)
                && text($0, kAXValueAttribute) == exactSourceIdentifier
        },
        children: { try attr($0, kAXChildrenAttribute) as? [AXUIElement] ?? [] }
    )
}
func readResult<Value>(_ body: () throws -> Value) -> Result<Value, AXReadFailure> {
    do { return .success(try body()) }
    catch let failure as AXReadFailure { return .failure(failure) }
    catch { return .failure(.nonBenign(.failure)) }
}
func setBool(_ element: AXUIElement, _ name: String, _ value: Bool) -> AXError {
    AXUIElementSetAttributeValue(element, name as CFString, value as CFBoolean)
}
func setPoint(_ element: AXUIElement, _ value: CGPoint) -> AXError {
    var value = value
    return AXUIElementSetAttributeValue(element, kAXPositionAttribute as CFString, AXValueCreate(.cgPoint, &value)!)
}
func setSize(_ element: AXUIElement, _ value: CGSize) -> AXError {
    var value = value
    return AXUIElementSetAttributeValue(element, kAXSizeAttribute as CFString, AXValueCreate(.cgSize, &value)!)
}
func restore(_ state: WindowState, to window: AXUIElement) -> Bool {
    var success = true
    if state.source {
        success = setSize(window, CGSize(width: state.width, height: state.height)) == .success && success
        success = setPoint(window, CGPoint(x: state.x, y: state.y)) == .success && success
    }
    success = setBool(window, kAXMinimizedAttribute, state.minimized) == .success && success
    return success
}

guard let finder = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.finder").first else {
    fputs("\(preStateFailureLine(.finderNotRunning))\n", stderr)
    exit(66)
}
let app = AXUIElementCreateApplication(finder.processIdentifier)
let windows: [AXUIElement]
do {
    guard let value = try attr(app, kAXWindowsAttribute) as? [AXUIElement] else {
        fputs("\(preStateFailureLine(.finderWindowsReadFailed))\n", stderr)
        exit(67)
    }
    windows = value
} catch {
    fputs("\(preStateFailureLine(.finderWindowsReadFailed))\n", stderr)
    exit(67)
}

if mode == "isolate" {
    let matchCounts: Result<[Int], AXReadFailure>
    do { matchCounts = .success(try windows.map { try countExactSource($0) }) }
    catch let failure as AXReadFailure { matchCounts = .failure(failure) }
    guard let sourceIndex = try? uniqueSourceWindow(matchCounts) else {
        fputs("exact source must bind to exactly one Finder window\n", stderr)
        exit(68)
    }

    let planResult = buildIsolationPlan(
        sourceIndex: sourceIndex,
        windowCount: windows.count,
        windowID: { index in readResult { try number(windows[index], axWindowNumberAttribute) } },
        rect: { index in readResult { try rect(windows[index]) } },
        minimized: { index in readResult { try bool(windows[index], kAXMinimizedAttribute) } }
    )
    guard case .success(let plan) = planResult else {
        fputs("source binding or non-source identity failed closed\n", stderr)
        exit(69)
    }
    let source = windows[sourceIndex]
    let persistence = persistStateSnapshot(
        encode: { try JSONEncoder().encode(plan.states) },
        atomicWrite: { try $0.write(to: stateURL, options: .atomic) }
    )
    if case .failure(let failure) = persistence {
        fputs("\(preStateFailureLine(failure.stage))\n", stderr)
        exit(70)
    }

    let otherWindowIndices = zip(plan.states, plan.windowIndices).compactMap { state, index in
        state.source ? nil : index
    }
    let mutationResult = runIsolationMutationCore(
        otherWindowCount: otherWindowIndices.count,
        minimizeOther: { index in
            setBool(windows[otherWindowIndices[index]], kAXMinimizedAttribute, true) == .success
        },
        unminimizeSource: { setBool(source, kAXMinimizedAttribute, false) == .success },
        setSourceSize: { setSize(source, CGSize(width: 500, height: 320)) == .success },
        setSourcePosition: { setPoint(source, CGPoint(x: 10, y: 70)) == .success },
        raiseSource: { AXUIElementPerformAction(source, kAXRaiseAction as CFString) == .success },
        beforeReadback: { Thread.sleep(forTimeInterval: 0.8) },
        readback: {
            readResult {
                isIsolationReadbackCompatible(
                    exactUniqueBound: true,
                    minimized: try bool(source, kAXMinimizedAttribute),
                    windowRect: try rect(source),
                    displayBounds: activeDisplayBounds() ?? []
                )
            }
        }
    )
    if case .failure(let stage) = mutationResult {
        let failure = finishIsolationFailure(stage) {
            restoreRecorded(plan) { state, index in restore(state, to: windows[index]) }
        }
        fputs("\(failure.line)\n", stderr)
        exit(failure.exitCode)
    }
    print("isolated_mutable_windows=\(plan.states.count) skipped_immutable_windows=\(windows.count - plan.states.count) source=<QA_WINDOW> readback=PASS")
} else {
    let states = try JSONDecoder().decode([WindowState].self, from: Data(contentsOf: stateURL))
    let matchCounts: Result<[Int], AXReadFailure>
    do { matchCounts = .success(try windows.map { try countExactSource($0) }) }
    catch let failure as AXReadFailure { matchCounts = .failure(failure) }
    let sourceIndex = try? uniqueSourceWindow(matchCounts)
    let planResult = buildRestorePlan(
        states: states,
        sourceIndex: sourceIndex,
        windowCount: windows.count,
        windowID: { index in readResult { try number(windows[index], axWindowNumberAttribute) } },
        sourceRect: {
            guard let sourceIndex else { return .success(nil) }
            return readResult { try rect(windows[sourceIndex]) }
        },
        sourceMinimized: {
            guard let sourceIndex else { return .success(nil) }
            return readResult { try bool(windows[sourceIndex], kAXMinimizedAttribute) }
        }
    )
    guard case .success(let plan) = planResult else {
        fputs("Finder restore binding failed closed\n", stderr)
        exit(75)
    }
    var restored = 0
    var failures = 0
    for (state, index) in zip(plan.states, plan.windowIndices) {
        if restore(state, to: windows[index]) { restored += 1 } else { failures += 1 }
    }
    let summary = RestoreSummary(mutableRecorded: plan.states.count, restored: restored, mutationFailures: failures)
    print("restored=\(summary.restored) mutable_recorded=\(summary.mutableRecorded) failures=\(summary.mutationFailures)")
    exit(summary.exitCode)
}
