import XCTest

struct FlatSnapshotFilterNode {
  let isRoot: Bool
  let label: String
  let identifier: String
  let valueText: String?
  let visible: Bool

  func matchesScope(_ scope: String) -> Bool {
    let haystack = [label, identifier, valueText ?? ""].joined(separator: "\n")
    return haystack.localizedCaseInsensitiveContains(scope)
  }
}

struct FlatSnapshotFilterDecision {
  let include: Bool
  let insideMatchedScope: Bool
}

extension RunnerTests {
  func flatSnapshotFilterDecision(
    _ node: FlatSnapshotFilterNode,
    options: SnapshotOptions,
    insideMatchedScope: Bool
  ) -> FlatSnapshotFilterDecision {
    let scope = options.scope?.trimmingCharacters(in: .whitespacesAndNewlines)
    let scopeActive = scope?.isEmpty == false
    let matchesScope: Bool
    if scopeActive, let scope {
      matchesScope = node.matchesScope(scope)
    } else {
      matchesScope = false
    }
    let nowInsideScope = insideMatchedScope || matchesScope

    let include: Bool
    if node.isRoot {
      include = true
    } else if scopeActive && !nowInsideScope {
      include = false
    } else if options.interactiveOnly && !node.visible {
      include = false
    } else {
      include = true
    }

    return FlatSnapshotFilterDecision(include: include, insideMatchedScope: nowInsideScope)
  }

  func privateAXInteractiveCandidate(rawElementType: Int) -> Bool {
    guard let type = flatSnapshotElementType(rawElementType: rawElementType) else {
      return false
    }
    return interactiveTypes.contains(type) || Self.scrollContainerTypes.contains(type)
  }

  func flatSnapshotElementType(rawElementType: Int) -> XCUIElement.ElementType? {
    guard let raw = UInt(exactly: rawElementType),
      let type = XCUIElement.ElementType(rawValue: raw)
    else {
      return nil
    }
    return type
  }

}
