//
//  DebugReplaceableView.swift
//  OpenSwiftUICore
//
//  Audited for 7.2.5
//  Status: Complete
//  ID: 8F31ED3737048FE14E730EE04503F67D (SwiftUICore)

#if OPENSWIFTUI_SUPPORT_2025_API
package import OpenAttributeGraphShims

// MARK: - DebugReplaceableView

/// Erases view opaque result types in debug builds.
///
/// You don't use this type directly. Instead OpenSwiftUI creates this type on
/// your behalf when building in debug mode.
///
/// When in debug builds, OpenSwiftUI will erase all opaque result types to
/// `DebugReplaceableView`. This allows developer tools, such as Xcode Previews,
/// to replace the definition of the view without fully rebuilding.
///
/// As such, seeing this type in traces and the view debugger is expected when
/// building for debugging. This type erasure can impact performance, especially
/// when dealing with dynamic content (like content generated by a ForEach, or
/// List) so any performance testing should be done in release mode.
///
/// This type acts similarly to an `AnyView` in that it type-erases its content,
/// however it depends on the underlying type of the value not actually changing
/// as it is in place of an opaque result type. As such, it *should not be used
/// in app code*.
@available(OpenSwiftUI_v7_0, *)
public struct DebugReplaceableView: View, PrimitiveView {
    var storage: DebugReplaceableViewStorageBase
    
    /// Creates a debug replaceable view erasing the given view.
    ///
    /// You don't use this initializer directly. Instead OpenSwiftUI creates this
    /// type on your behalf when building in debug mode.
    ///
    /// This type acts similarly to an `AnyView` in that it type-erases its
    /// content, however it depends on the underlying type of the value not
    /// actually changing as it is in place of an opaque result type. As such,
    /// it *should not be used in app code*.
    @available(*, deprecated, message: "DebugReplaceableView should not be used directly, to type erase a View, you should use AnyView.")
    @_alwaysEmitIntoClient
    public init<V>(erasing view: V) where V: View {
        self.init(_erasing: view)
    }
    
    @usableFromInline
    internal init<V>(_erasing view: V) where V: View {
        if let replaceableView = view as? DebugReplaceableView {
            storage = replaceableView.storage
        } else {
            storage = DebugReplaceableViewStorage(view: view)
        }
    }
    
    nonisolated public static func _makeView(view: _GraphValue<Self>, inputs: _ViewInputs) -> _ViewOutputs {
        makeDynamicView(metadata: (), view: view, inputs: inputs)
    }

    nonisolated public static func _makeViewList(view: _GraphValue<Self>, inputs: _ViewListInputs) -> _ViewListOutputs {
        makeDynamicViewList(metadata: (), view: view, inputs: inputs)
    }
    
    @available(OpenSwiftUI_v2_0, *)
    nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? {
        let info = inputs.debugReplaceableViewInfo
        if info.countAsZero, let countedAsZero = info.countedAsZero {
            countedAsZero.pointee = true
        }
        return info.countAsZero ? 0 : nil
    }

    package func visitContent<Visitor: ViewVisitor>(_ visitor: inout Visitor) {
        storage.visitContent(&visitor)
    }

}
@available(*, unavailable)
extension DebugReplaceableView: Sendable {}

// MARK: - DebugReplaceableView: DynamicView

extension DebugReplaceableView: DynamicView {
    package static var canTransition: Bool { false }

    package func childInfo(metadata: ()) -> (any Any.Type, UniqueID?) {
        (storage.childType, nil)
    }
    
    package func makeChildView(metadata: (), view: Attribute<DebugReplaceableView>, inputs: _ViewInputs) -> _ViewOutputs {
        storage.makeChildView(view: view, inputs: inputs)
    }
    
    package func makeChildViewList(metadata: (), view: Attribute<DebugReplaceableView>, inputs: _ViewListInputs) -> _ViewListOutputs {
        storage.makeChildViewList(view: view, inputs: inputs)
    }
}

// MARK: - DebugReplaceableViewStorageBase

@available(OpenSwiftUI_v7_0, *)
@usableFromInline
internal class DebugReplaceableViewStorageBase {
    fileprivate var childType: any Any.Type {
        _openSwiftUIBaseClassAbstractMethod()
    }

    fileprivate func makeChildView(view: Attribute<DebugReplaceableView>, inputs: _ViewInputs) -> _ViewOutputs {
        _openSwiftUIBaseClassAbstractMethod()
    }

    fileprivate func makeChildViewList(view: Attribute<DebugReplaceableView>, inputs: _ViewListInputs) -> _ViewListOutputs {
        _openSwiftUIBaseClassAbstractMethod()
    }

    fileprivate func visitContent<Visitor>(_ visitor: inout Visitor) where Visitor: ViewVisitor {
        _openSwiftUIBaseClassAbstractMethod()
    }
}

@available(*, unavailable)
extension DebugReplaceableViewStorageBase: Sendable {}

// MARK: - DebugReplaceableViewStorage

private final class DebugReplaceableViewStorage<V>: DebugReplaceableViewStorageBase where V: View {
    let view: V
    
    init(view: V) {
        self.view = view
        super.init()
    }
    
    override var childType: any Any.Type {
        V.self
    }
    
    override func makeChildView(
        view: Attribute<DebugReplaceableView>,
        inputs: _ViewInputs
    ) -> _ViewOutputs {
        var inputs = inputs
        inputs.base.pushStableType(V.self)
        let childView = Attribute(DebugReplaceableViewChild<V>(view: view))
        childView.value = self.view
        return V.makeDebuggableView(view: _GraphValue(childView), inputs: inputs)
    }
    
    override func makeChildViewList(
        view: Attribute<DebugReplaceableView>,
        inputs: _ViewListInputs
    ) -> _ViewListOutputs {
        var inputs = inputs
        inputs.base.pushStableType(V.self)
        let childView = Attribute(DebugReplaceableViewChild<V>(view: view))
        childView.value = self.view
        return V.makeDebuggableViewList(view: _GraphValue(childView), inputs: inputs)
    }
    
    override func visitContent<Visitor>(_ visitor: inout Visitor) where Visitor : ViewVisitor {
        visitor.visit(view)
    }
}

// MARK: - DebugReplaceableViewInfo

package struct DebugReplaceableViewInfo {
    package var countAsZero: Bool
    package var countedAsZero: UnsafeMutablePointer<Bool>?

    package init(countAsZero: Bool, countedAsZero: UnsafeMutablePointer<Bool>?) {
        self.countAsZero = countAsZero
        self.countedAsZero = countedAsZero
    }
}

// MARK: - DebugReplaceableViewChild

fileprivate struct DebugReplaceableViewChild<V>: StatefulRule, AsyncAttribute, CustomStringConvertible where V: View {
    @Attribute var view: DebugReplaceableView

    typealias Value = V

    func updateValue() {
        value = (view.storage as! DebugReplaceableViewStorage<V>).view
    }

    var description: String {
        "\(V.self)"
    }
}
#endif
