import HUD
import DrawerFeature
import UIKit
import Theme
import Shared
import Combine
import DependencyInjection
import ScrollViewController

public final class SettingsController: UIViewController {
    @Dependency private var hud: HUD
    @Dependency private var coordinator: SettingsCoordinating
    @Dependency private var statusBarController: StatusBarStyleControlling

    lazy private var scrollViewController = ScrollViewController()
    lazy private var screenView = SettingsView {
        switch $0 {
        case .icognitoKeyboard:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Icognito.title,
                subtitle: Localized.Settings.InfoDrawer.Icognito.subtitle
            )
        case .biometrics:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Biometrics.title,
                subtitle: Localized.Settings.InfoDrawer.Biometrics.subtitle
            )
        case .notifications:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Notifications.title,
                subtitle: Localized.Settings.InfoDrawer.Notifications.subtitle,
                urlString: "https://links.xx.network/denseids"
            )

        case .dummyTraffic:
            self.presentInfo(
                title: Localized.Settings.InfoDrawer.Traffic.title,
                subtitle: Localized.Settings.InfoDrawer.Traffic.subtitle,
                urlString: "https://links.xx.network/covertraffic"
            )
        }
    }

    private let viewModel = SettingsViewModel()
    private var cancellables = Set<AnyCancellable>()
    private var drawerCancellables = Set<AnyCancellable>()

    public override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        statusBarController.style.send(.darkContent)
        navigationController?.navigationBar
            .customize(backgroundColor: Asset.neutralWhite.color)
    }

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

        setupNavigationBar()
        setupScrollView()
        setupBindings()

        viewModel.loadCachedSettings()
    }

    private func setupNavigationBar() {
        navigationItem.backButtonTitle = ""

        let titleLabel = UILabel()
        titleLabel.text = Localized.Settings.title
        titleLabel.textColor = Asset.neutralActive.color
        titleLabel.font = Fonts.Mulish.semiBold.font(size: 18.0)

        let menuButton = UIButton()
        menuButton.tintColor = Asset.neutralDark.color
        menuButton.setImage(Asset.chatListMenu.image, for: .normal)
        menuButton.addTarget(self, action: #selector(didTapMenu), for: .touchUpInside)
        menuButton.snp.makeConstraints { $0.width.equalTo(50) }

        navigationItem.leftBarButtonItem = UIBarButtonItem(
            customView: UIStackView(arrangedSubviews: [menuButton, titleLabel])
        )
    }

    private func setupScrollView() {
        scrollViewController.view.backgroundColor = Asset.neutralWhite.color

        addChild(scrollViewController)
        view.addSubview(scrollViewController.view)

        scrollViewController.view.snp.makeConstraints { $0.edges.equalToSuperview() }
        scrollViewController.didMove(toParent: self)
        scrollViewController.contentView = screenView
    }

    private func setupBindings() {
        viewModel.hud
            .receive(on: DispatchQueue.main)
            .sink { [hud] in hud.update(with: $0) }
            .store(in: &cancellables)

        screenView.inAppNotifications.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleInAppNotifications() }
            .store(in: &cancellables)

        screenView.dummyTraffic.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleDummyTraffic() }
            .store(in: &cancellables)

        screenView.remoteNotifications.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didTogglePushNotifications() }
            .store(in: &cancellables)

        screenView.hideActiveApp.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleHideActiveApps() }
            .store(in: &cancellables)

        screenView.icognitoKeyboard.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleIcognitoKeyboard() }
            .store(in: &cancellables)

        screenView.biometrics.switcherView
            .publisher(for: .valueChanged)
            .sink { [weak viewModel] in viewModel?.didToggleBiometrics() }
            .store(in: &cancellables)

        screenView.privacyPolicyButton
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in
                presentDrawer(
                    title: Localized.Settings.Drawer.title(Localized.Settings.privacyPolicy),
                    subtitle: Localized.Settings.Drawer.subtitle(Localized.Settings.privacyPolicy),
                    actionTitle: Localized.ChatList.Dashboard.open) {
                        guard let url = URL(string: "https://elixxir.io/privategrity-corporation-privacy-policy/") else { return }
                        UIApplication.shared.open(url, options: [:])
                    }
            }.store(in: &cancellables)

        screenView.disclosuresButton
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in
                presentDrawer(
                    title: Localized.Settings.Drawer.title(Localized.Settings.disclosures),
                    subtitle: Localized.Settings.Drawer.subtitle(Localized.Settings.disclosures),
                    actionTitle: Localized.ChatList.Dashboard.open) {
                        guard let url = URL(string: "https://elixxir.io/privategrity-corporation-terms-of-use/") else { return }
                        UIApplication.shared.open(url, options: [:])
                    }
            }.store(in: &cancellables)

        screenView.deleteButton
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in coordinator.toDelete(from: self) }
            .store(in: &cancellables)

        screenView.accountBackupButton
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in coordinator.toBackup(from: self) }
            .store(in: &cancellables)

        screenView.advancedButton
            .publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] in coordinator.toAdvanced(from: self) }
            .store(in: &cancellables)

        viewModel.state
            .map(\.isBiometricsPossible)
            .removeDuplicates()
            .receive(on: DispatchQueue.main)
            .sink { [weak screenView] in screenView?.biometrics.switcherView.isEnabled = $0 }
            .store(in: &cancellables)

        viewModel.state
            .removeDuplicates()
            .receive(on: DispatchQueue.main)
            .sink { [unowned self] state in
                screenView.biometrics.switcherView.setOn(state.isBiometricsEnabled, animated: true)
                screenView.hideActiveApp.switcherView.setOn(state.isHideActiveApps, animated: true)
                screenView.icognitoKeyboard.switcherView.setOn(state.isIcognitoKeyboard, animated: true)
                screenView.inAppNotifications.switcherView.setOn(state.isInAppNotification, animated: true)
                screenView.remoteNotifications.switcherView.setOn(state.isPushNotification, animated: true)
                screenView.dummyTraffic.switcherView.setOn(state.isDummyTrafficOn, animated: true)
            }.store(in: &cancellables)
    }

    private func presentDrawer(
        title: String,
        subtitle: String,
        actionTitle: String,
        action: @escaping () -> Void
    ) {
        let actionButton = CapsuleButton()
        actionButton.setStyle(.red)
        actionButton.setTitle(actionTitle, for: .normal)

        let cancelButton = CapsuleButton()
        cancelButton.setStyle(.seeThrough)
        cancelButton.setTitle(Localized.ChatList.Dashboard.cancel, for: .normal)

        let drawer = DrawerController(with: [
            DrawerImage(
                image: Asset.drawerNegative.image
            ),
            DrawerText(
                font: Fonts.Mulish.semiBold.font(size: 18.0),
                text: title,
                color: Asset.neutralActive.color
            ),
            DrawerText(
                font: Fonts.Mulish.semiBold.font(size: 14.0),
                text: subtitle,
                color: Asset.neutralWeak.color,
                lineHeightMultiple: 1.35,
                spacingAfter: 25
            ),
            DrawerStack(
                spacing: 20.0,
                views: [actionButton, cancelButton]
            )
        ])

        actionButton.publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink {
                drawer.dismiss(animated: true) { [weak self] in
                    guard let self = self else { return }
                    self.drawerCancellables.removeAll()

                    action()
                }
            }.store(in: &drawerCancellables)

        cancelButton.publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink {
                drawer.dismiss(animated: true) { [weak self] in
                    self?.drawerCancellables.removeAll()
                }
            }.store(in: &drawerCancellables)

        coordinator.toDrawer(drawer, from: self)
    }

    @objc private func didTapMenu() {
        coordinator.toSideMenu(from: self)
    }
}

extension SettingsController {
    private func presentInfo(
        title: String,
        subtitle: String,
        urlString: String = ""
    ) {
        let actionButton = CapsuleButton()
        actionButton.set(
            style: .seeThrough,
            title: Localized.Settings.InfoDrawer.action
        )

        let drawer = DrawerController(with: [
            DrawerText(
                font: Fonts.Mulish.bold.font(size: 26.0),
                text: title,
                color: Asset.neutralActive.color,
                alignment: .left,
                spacingAfter: 19
            ),
            DrawerLinkText(
                text: subtitle,
                urlString: urlString,
                spacingAfter: 37
            ),
            DrawerStack(views: [
                actionButton,
                FlexibleSpace()
            ])
        ])

        actionButton.publisher(for: .touchUpInside)
            .receive(on: DispatchQueue.main)
            .sink {
                drawer.dismiss(animated: true) { [weak self] in
                    guard let self = self else { return }
                    self.drawerCancellables.removeAll()
                }
            }.store(in: &drawerCancellables)

        coordinator.toDrawer(drawer, from: self)
    }
}