import AppCore
import ComposableArchitecture
import Foundation
import XXMessengerClient
import XXModels

public struct NewGroupComponent: ReducerProtocol {
  public struct State: Equatable {
    public init(
      contacts: IdentifiedArrayOf<XXModels.Contact> = [],
      members: IdentifiedArrayOf<XXModels.Contact> = []
    ) {
      self.contacts = contacts
      self.members = members
    }

    public var contacts: IdentifiedArrayOf<XXModels.Contact>
    public var members: IdentifiedArrayOf<XXModels.Contact>
  }

  public enum Action: Equatable {
    case start
    case didFetchContacts([XXModels.Contact])
    case didSelectContact(XXModels.Contact)
    case didFinish
  }

  public init() {}

  @Dependency(\.app.messenger) var messenger: Messenger
  @Dependency(\.app.dbManager.getDB) var db: DBManagerGetDB
  @Dependency(\.app.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
  @Dependency(\.app.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>

  public func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
    switch action {
    case .start:
      let myId = try? messenger.e2e.tryGet().getContact().getId()
      return Effect
        .catching { try db() }
        .flatMap { $0.fetchContactsPublisher(.init()) }
        .assertNoFailure()
        .map { $0.filter { $0.id != myId } }
        .map(Action.didFetchContacts)
        .subscribe(on: bgQueue)
        .receive(on: mainQueue)
        .eraseToEffect()

    case .didFetchContacts(let contacts):
      state.contacts = IdentifiedArray(uniqueElements: contacts)
      return .none

    case .didSelectContact(let contact):
      if state.members.contains(contact) {
        state.members.remove(contact)
      } else {
        state.members.append(contact)
      }
      return .none

    case .didFinish:
      return .none
    }
  }
}