/*
Example usage:

    confirmationDialog(
      store: store.scope(state: \.destination, action: UserRecipesListReducer.Action.destination),
      state: /UserRecipesListReducer.Destination.State.confirmation,
      action: UserRecipesListReducer.Destination.Action.confirmation
    ).store(in: &subscriptions)

    alert(
      store: store.scope(state: \.destination, action: UserRecipesListReducer.Action.destination),
      state: /UserRecipesListReducer.Destination.State.alert,
      action: UserRecipesListReducer.Destination.Action.alert
    ).store(in: &subscriptions)

*/

extension StoreViewController {

  func alert<DestinationState, DestinationAction, Action>(
    store: Store<DestinationState?, PresentationAction<DestinationAction>>,
    state toAlertState: @escaping (DestinationState) -> AlertState<Action>?,
    action fromAlertAction: @escaping (Action) -> DestinationAction
  ) -> any Cancellable {
    self.alert(
      store: store.scope(
        state: { $0.flatMap(toAlertState) },
        action: {
          switch $0 {
          case .dismiss: return .dismiss
          case let .presented(action): return .presented(fromAlertAction(action))
          }
        }
      )
    )
  }

  func alert<Action>(
    store: Store<AlertState<Action>?, PresentationAction<Action>>
  ) -> any Cancellable {
    let viewStore = ViewStore(store, observe: { $0 }, removeDuplicates: { ($0 != nil) == ($1 != nil) })
    return viewStore.publisher.sink { alertState in
      if let alertState {
        let alertController = UIAlertController(state: alertState) { action in
          if let action {
            viewStore.send(.presented(action))
          }
        }
        self.present(alertController, animated: true)
      } else {
        self.dismiss(animated: true)
      }
    }
  }

  func confirmationDialog<DestinationState, DestinationAction, Action>(
    store: Store<DestinationState?, PresentationAction<DestinationAction>>,
    state toConfirmationDialogState: @escaping (DestinationState) -> ConfirmationDialogState<Action>?,
    action fromConfirmationAction: @escaping (Action) -> DestinationAction
  ) -> any Cancellable {
    self.confirmationDialog(
      store: store.scope(
        state: { $0.flatMap(toConfirmationDialogState) },
        action: {
          switch $0 {
          case .dismiss: return .dismiss
          case let .presented(action): return .presented(fromConfirmationAction(action))
          }
        }
      )
    )
  }

  func confirmationDialog<Action>(
    store: Store<ConfirmationDialogState<Action>?, PresentationAction<Action>>
  ) -> any Cancellable {
    let viewStore = ViewStore(store, observe: { $0 }, removeDuplicates: { ($0 != nil) == ($1 != nil) })
    return viewStore.publisher.sink { confirmationState in
      if let confirmationState {
        let alertController = UIAlertController(state: confirmationState) { action in
          if let action {
            viewStore.send(.presented(action))
          }
        }
        self.present(alertController, animated: true)
      } else {
        self.dismiss(animated: true)
      }
    }
  }
}