import UIKit
import Shared
import Combine
import Dependencies
import AppResources
import DrawerFeature
import AppNavigation

public final class LaunchController: UIViewController {
  @Dependency(\.navigator) var navigator

  private lazy var screenView = LaunchView()
  private let viewModel = LaunchViewModel()
  private var cancellables = Set<AnyCancellable>()
  private var drawerCancellables = Set<AnyCancellable>()

  public var pendingPushNotificationRoute: PushNotificationRouter.Route?

  public override func loadView() {
    view = screenView
  }

  public override func viewDidLoad() {
    super.viewDidLoad()

    viewModel
      .statePublisher
      .receive(on: DispatchQueue.main)
      .sink { [unowned self] in
        guard $0.shouldPushEndDestination != .some(.chats) else {
          guard $0.shouldShowTerms == false else {
            navigator.perform(PresentTermsAndConditions(replacing: true, on: navigationController!))
            return
          }
          if let route = pendingPushNotificationRoute {
            hasPendingPushRoute(route)
            return
          }
          navigator.perform(PresentChatList(on: navigationController!))
          return
        }
        guard $0.shouldPushEndDestination != .some(.onboarding) else {
          navigator.perform(PresentOnboardingStart(on: navigationController!))
          return
        }
        if let update = $0.shouldOfferUpdate {
          offerUpdate(model: update)
        }
      }.store(in: &cancellables)

    viewModel.startLaunch()
  }

  private func hasPendingPushRoute(_ route: PushNotificationRouter.Route) {
    switch route {
    case .requests:
      navigator.perform(PresentRequests(on: navigationController!))
    case .search(username: let username):
      navigator.perform(PresentSearch(
        searching: username,
        fromOnboarding: true,
        on: navigationController!))
    case .groupChat(id: let groupId):
      if let info = viewModel.getGroupInfoWith(groupId: groupId) {
        navigator.perform(PresentGroupChat(groupInfo: info, on: navigationController!))
        return
      }
      navigator.perform(PresentChatList(on: navigationController!))
    case .contactChat(id: let userId):
      if let model = viewModel.getContactWith(userId: userId) {
        navigator.perform(PresentChat(contact: model, on: navigationController!))
        return
      }
      navigator.perform(PresentChatList(on: navigationController!))
    }
  }

  private func offerUpdate(model: LaunchViewModel.UpdateModel) {
    let updateButton = CapsuleButton()
    updateButton.set(
      style: .brandColored,
      title: model.positiveActionTitle
    )
    let notNowButton = CapsuleButton()
    if let negativeTitle = model.negativeActionTitle {
      notNowButton.set(
        style: .red,
        title: negativeTitle
      )
    }
    updateButton
      .publisher(for: .touchUpInside)
      .receive(on: DispatchQueue.main)
      .sink { [unowned self] in
        navigator.perform(DismissModal(from: self)) {
          self.drawerCancellables.removeAll()
          UIApplication.shared.open(.init(string: model.urlString)!)
        }
      }.store(in: &drawerCancellables)

    notNowButton
      .publisher(for: .touchUpInside)
      .receive(on: DispatchQueue.main)
      .sink { [unowned self] in
        navigator.perform(DismissModal(from: self)) {
          self.drawerCancellables.removeAll()
          self.viewModel.didRefuseUpdating()
        }
      }.store(in: &drawerCancellables)

    var actions: [UIView] = [updateButton]
    if model.negativeActionTitle != nil {
      actions.append(notNowButton)
    }

    navigator.perform(PresentDrawer(items: [
      DrawerText(
        font: Fonts.Mulish.bold.font(size: 26.0),
        text: "App Update",
        color: Asset.neutralActive.color,
        alignment: .center,
        spacingAfter: 19
      ),
      DrawerText(
        font: Fonts.Mulish.regular.font(size: 16.0),
        text: model.content,
        color: Asset.neutralBody.color,
        alignment: .center,
        spacingAfter: 19
      ),
      DrawerStack(
        axis: .vertical,
        views: actions
      )
    ], isDismissable: false, from: self))
  }
}