// generated by bun run generate from the SwiftUI SDK and codegen/catalog.ts.
// edit the generator or catalog, then regenerate.
import SwiftUI
import UIKit
import PhotosUI
import CoreTransferable
import UniformTypeIdentifiers

private final class PhotosPickerModel: ObservableObject {
  @Published var label: String = ""
  @Published var disabled: Bool = false
  @Published var systemImage: String = ""
  @Published var maxSelectionCount: Double = 1
  @Published var selectionBehavior: String = "default"
  @Published var filter: String = "any"
  @Published var preferredItemEncoding: String = "automatic"
  @Published var accessibility = OneNativeAccessibility()
  @Published var swiftStyle = OneNativeStyle()
  var active = false
  var onSDKEvent: ((String, String) -> Void)?
  func emitSDKEvent(_ name: String, _ value: String) { if active { onSDKEvent?(name, value) } }

  var onPick: ((String, Double, Double, Int) -> Void)?
  private var pickCount = 0
  func pick(_ url: String, _ index: Double, _ count: Double) {
    guard active, !disabled else { return }
    pickCount += 1
    onPick?(url, index, count, pickCount)
  }
  var onPickItemIdentifier: ((String, Double, Double, Int) -> Void)?
  private var pickItemIdentifierCount = 0
  func pickItemIdentifier(_ itemIdentifier: String, _ index: Double, _ count: Double) {
    guard active, !disabled else { return }
    pickItemIdentifierCount += 1
    onPickItemIdentifier?(itemIdentifier, index, count, pickItemIdentifierCount)
  }
  var onPickError: ((String, Int) -> Void)?
  private var pickErrorCount = 0
  func pickError(_ message: String) {
    guard active, !disabled else { return }
    pickErrorCount += 1
    onPickError?(message, pickErrorCount)
  }
}
@objcMembers public final class OneNativePhotosPickerView: UIView, OneNativeComposable {
  public var onSDKEvent: ((String, String) -> Void)?

  public var onPick: ((String, Double, Double, Int) -> Void)?
  public var onPickItemIdentifier: ((String, Double, Double, Int) -> Void)?
  public var onPickError: ((String, Int) -> Void)?
  private var model = PhotosPickerModel()
  public var onHeight: ((CGFloat) -> Void)?
  private var controller: OneNativeHostingController<OneNativeMeasuredStandalone<PhotosPickerContent>>?
  public override init(frame: CGRect) { super.init(frame: frame) }
  required init?(coder: NSCoder) { fatalError("init(coder:) is unavailable") }
  public func configureAccessibility(_ label: String, hint: String, value: String, identifier: String) {
    let next = OneNativeAccessibility(label: label, hint: hint, value: value, identifier: identifier)
    if model.accessibility != next { model.accessibility = next }
  }
  public func configureStyle(_ style: [String: Any]) {
    let next = OneNativeStyle(dictionary: style)
    if model.swiftStyle != next {
      let previousRows = model.swiftStyle.sdkModifiers.filter { $0.first?.hasPrefix("listRow") == true }
      let nextRows = next.sdkModifiers.filter { $0.first?.hasPrefix("listRow") == true }
      model.swiftStyle = next
      if previousRows != nextRows { compositionParent?.refreshRow(for: self) }
    }
  }
  public func configure(_ label: String, disabled: Bool, systemImage: String, maxSelectionCount: Double, selectionBehavior: String, filter: String, preferredItemEncoding: String) {
    if model.label != label { model.label = label }
    if model.disabled != disabled { model.disabled = disabled }
    if model.systemImage != systemImage { model.systemImage = systemImage }
    if model.maxSelectionCount != maxSelectionCount { model.maxSelectionCount = maxSelectionCount }
    if model.selectionBehavior != selectionBehavior { model.selectionBehavior = selectionBehavior }
    if model.filter != filter { model.filter = filter }
    if model.preferredItemEncoding != preferredItemEncoding { model.preferredItemEncoding = preferredItemEncoding }
  }


  private weak var compositionParent: OneNativeCompositionParent?
  public func compositionContent() -> AnyView { AnyView(PhotosPickerContent(model: model)) }
  // composed, activation follows the parent: a subtree mounted before root attachment
  // stays silent until the root attaches.
  public func composeInto(_ parent: OneNativeCompositionParent) {
    controller?.detach(); controller = nil
    compositionParent = parent
    bindCallbacks()
    model.active = parent.compositionActive
  }
  public func decompose() { compositionParent = nil; model.active = false }
  public func propagateActive(_ active: Bool) { model.active = active }
  public override func didMoveToWindow() { super.didMoveToWindow(); updateHost() }
  public override func layoutSubviews() { super.layoutSubviews(); updateHost() }
  private func bindCallbacks() {
    model.onSDKEvent = { [weak self] name, value in self?.onSDKEvent?(name, value) }

    model.onPick = { [weak self] url, index, count, pickCount in self?.onPick?(url, index, count, pickCount) }
    model.onPickItemIdentifier = { [weak self] itemIdentifier, index, count, pickItemIdentifierCount in self?.onPickItemIdentifier?(itemIdentifier, index, count, pickItemIdentifierCount) }
    model.onPickError = { [weak self] message, pickErrorCount in self?.onPickError?(message, pickErrorCount) }
  }
  private func updateHost() {
    guard compositionParent == nil else { return }
    model.active = false
    guard window != nil else { controller?.detach(); return }
    if controller == nil {
      bindCallbacks()
      controller = OneNativeHostingController(rootView: OneNativeMeasuredStandalone(content: PhotosPickerContent(model: model), onHeight: { [weak self] height in self?.onHeight?(height) }))
    }
    controller?.attach(to: self)
    model.active = controller?.isAttached == true
  }
  public func reset() {
    compositionParent = nil
    model.active = false; model.onSDKEvent = nil; model.onPick = nil; model.onPickItemIdentifier = nil; model.onPickError = nil
    controller?.detach(); controller = nil; model = PhotosPickerModel()
  }
}
private struct PhotosPickerContent: View {
  @ObservedObject var model: PhotosPickerModel
  var body: some View {
    PhotosPickerSurface(model: model)
      .disabled(model.disabled)
      .oneNativeAccessibility(model.accessibility)
      .oneNativeStyle(model.swiftStyle, emit: model.emitSDKEvent)
  }
}
// PHPickerFilter is PhotosUI's own type rather than its SwiftUI overlay's, so the generator
// does not read it and cannot select these cases. swiftc -typecheck against the SDK is what
// proves each one still exists.
private func oneNativePhotosFilter(_ value: String) -> PHPickerFilter? {
  switch value {
  case "any": return nil
  case "images": return .images
  case "videos": return .videos
  case "livePhotos": return .livePhotos
  case "screenshots": return .screenshots
  case "screenRecordings": return .screenRecordings
  case "slomoVideos": return .slomoVideos
  case "timelapseVideos": return .timelapseVideos
  case "cinematicVideos": return .cinematicVideos
  case "depthEffectPhotos": return .depthEffectPhotos
  case "bursts": return .bursts
  case "panoramas": return .panoramas
  default: preconditionFailure("invalid PHPickerFilter: \(value)")
  }
}
func oneNativePickerFile(_ data: Data, extension ext: String) throws -> URL {
  let url = FileManager.default.temporaryDirectory
    .appendingPathComponent("one-native-photo-\(UUID().uuidString)")
    .appendingPathExtension(ext)
  try data.write(to: url)
  return url
}
private struct PhotosPickerSurface: View {
  @ObservedObject var model: PhotosPickerModel
  // the picker owns its selection; React never sets it, so it lives here rather than in the
  // model and is emptied as soon as the items have been handed on.
  @State private var selection: [PhotosPickerItem] = []
  var body: some View {
    PhotosPicker(
      selection: $selection,
      maxSelectionCount: model.maxSelectionCount > 0 ? Int(model.maxSelectionCount) : nil,
      selectionBehavior: OneNativeGenerated.photosPickerSelectionBehavior(model.selectionBehavior),
      matching: oneNativePhotosFilter(model.filter),
      preferredItemEncoding: OneNativeGenerated.encodingDisambiguationPolicy(model.preferredItemEncoding)
    ) {
      if model.systemImage.isEmpty { Text(model.label) }
      else { Label(model.label, systemImage: model.systemImage) }
    }
    .onChange(of: selection) { _, items in
      guard !items.isEmpty else { return }
      selection = []
      deliver(items)
    }
  }
  // one task per item: they finish out of order, which is why the event carries its index.
  private func deliver(_ items: [PhotosPickerItem]) {
    let count = items.count
    for (index, item) in items.enumerated() {
      if let id = item.itemIdentifier { model.pickItemIdentifier(id, Double(index), Double(count)) }
      Task { @MainActor in
        do {
          guard let data = try await item.loadTransferable(type: Data.self) else {
            model.pickError("the picked item carries no data")
            return
          }
          let url = try oneNativePickerFile(data, extension: item.supportedContentTypes.first?.preferredFilenameExtension ?? "dat")
          model.pick(url.absoluteString, Double(index), Double(count))
        } catch {
          model.pickError(error.localizedDescription)
        }
      }
    }
  }
}
