import Foundation
import XCTestDynamicOverlay
import XXClient

public struct MessengerSearchContacts {
  public struct Query: Equatable {
    public init(
      username: String? = nil,
      email: String? = nil,
      phone: String? = nil
    ) {
      self.username = username
      self.email = email
      self.phone = phone
    }

    public var username: String?
    public var email: String?
    public var phone: String?
  }

  public enum Error: Swift.Error, Equatable {
    case notConnected
    case notLoggedIn
  }

  public var run: (Query) throws -> [Contact]

  public func callAsFunction(query: Query) throws -> [Contact] {
    try run(query)
  }
}

extension MessengerSearchContacts {
  public static func live(_ env: MessengerEnvironment) -> MessengerSearchContacts {
    MessengerSearchContacts { query in
      guard let e2e = env.e2e() else {
        throw Error.notConnected
      }
      guard let ud = env.ud() else {
        throw Error.notLoggedIn
      }
      var result: Result<[Contact], Swift.Error>!
      let semaphore = DispatchSemaphore(value: 0)
      _ = try env.searchUD(
        e2eId: e2e.getId(),
        udContact: try ud.getContact(),
        facts: query.facts,
        singleRequestParamsJSON: env.getSingleUseParams(),
        callback: .init { searchResult in
          switch searchResult {
          case .success(let contacts):
            result = .success(contacts)
          case .failure(let error):
            result = .failure(error)
          }
          semaphore.signal()
        }
      )
      semaphore.wait()
      return try result.get()
    }
  }
}

extension MessengerSearchContacts.Query {
  public var isEmpty: Bool {
    [username, email, phone]
      .compactMap { $0 }
      .map { $0.isEmpty == false }
      .contains(where: { $0 == true }) == false
  }

  var facts: [Fact] {
    var facts: [Fact] = []
    if let username = username, username.isEmpty == false {
      facts.set(.username, username)
    }
    if let email = email, email.isEmpty == false {
      facts.set(.email, email)
    }
    if let phone = phone, phone.isEmpty == false {
      facts.set(.phone, phone)
    }
    return facts
  }
}

extension MessengerSearchContacts {
  public static let unimplemented = MessengerSearchContacts(
    run: XCTUnimplemented("\(Self.self)")
  )
}