//
//  MastodonConfirmEmailViewController.swift
//  Mastodon
//
//  Created by sxiaojian on 2021/2/23.
//

import Combine
import MastodonSDK
import UIKit
import MastodonAsset
import MastodonCore
import MastodonUI
import MastodonLocalization

final class MastodonConfirmEmailViewController: UIViewController, NeedsDependency {
    
    var disposeBag = Set<AnyCancellable>()

    weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
    weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }

    var viewModel: MastodonConfirmEmailViewModel!

    let stackView = UIStackView()

    private(set) lazy var subtitleLabel: UILabel = {
        let label = UILabel()
        label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: UIFont.systemFont(ofSize: 17))
        label.textColor = .label
        label.numberOfLines = 0
        return label
    }()
    
    let emailImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.image = Asset.Asset.email.image
        imageView.backgroundColor = .clear
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()

    let resendEmailButton: UIButton = {

        let boldFont = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .bold))
        let regularFont = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular))

        var buttonConfiguration = UIButton.Configuration.plain()
        var boldResendString = AttributedString(L10n.Scene.ConfirmEmail.DidntGetLink.resendIn(60), attributes: .init([.font: boldFont]))
        var attributedTitle = AttributedString(L10n.Scene.ConfirmEmail.DidntGetLink.prefix, attributes: .init([.font: regularFont]))

        attributedTitle.append(AttributedString(" "))
        attributedTitle.append(boldResendString)

        buttonConfiguration.attributedTitle = attributedTitle

        let button = UIButton(configuration: buttonConfiguration)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.isEnabled = false

        return button
    }()

    var resendButtonTimer: Timer?
}

extension MastodonConfirmEmailViewController {

    override func viewDidLoad() {

        setupOnboardingAppearance()
        configureMargin()

        subtitleLabel.text = L10n.Scene.ConfirmEmail.tapTheLinkWeEmailedToYouToVerifyYourAccount(viewModel.email)

        resendEmailButton.addTarget(self, action: #selector(MastodonConfirmEmailViewController.resendButtonPressed(_:)), for: .touchUpInside)

        // stackView
        stackView.axis = .vertical
        stackView.distribution = .fill
        stackView.spacing = 10
        stackView.layoutMargins = UIEdgeInsets(top: 10, left: 0, bottom: 23, right: 0)
        stackView.isLayoutMarginsRelativeArrangement = true
        stackView.addArrangedSubview(subtitleLabel)
        stackView.addArrangedSubview(emailImageView)
        stackView.addArrangedSubview(resendEmailButton)
        emailImageView.setContentHuggingPriority(.defaultLow, for: .vertical)
        emailImageView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)

        view.addSubview(stackView)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor),
            stackView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor),
        ])
        
        self.viewModel.timestampUpdatePublisher
            .sink { [weak self] _ in
                guard let self = self else { return }
                AuthenticationViewModel.verifyAndSaveAuthentication(context: self.context, info: self.viewModel.authenticateInfo, userToken: self.viewModel.userToken)
                    .receive(on: DispatchQueue.main)
                    .sink { completion in
                        switch completion {
                        case .failure(_):
                                break
                        case .finished:
                            // upload avatar and set display name in the background
                            Just(self.viewModel.userToken.accessToken)
                                .asyncMap { token in
                                    try await self.context.apiService.accountUpdateCredentials(
                                        domain: self.viewModel.authenticateInfo.domain,
                                        query: self.viewModel.updateCredentialQuery,
                                        authorization: Mastodon.API.OAuth.Authorization(accessToken: token)
                                    )
                                }
                                .retry(3)
                                .sink { completion in
                                    switch completion {
                                    case .failure(_):
                                            break
                                        case .finished:
                                            break
                                    }
                                } receiveValue: { _ in
                                    // do nothing
                                }
                                .store(in: &self.context.disposeBag)    // execute in the background
                        }   // end switch
                    } receiveValue: { response in
                        self.coordinator.setup()
                        // self.dismiss(animated: true, completion: nil)
                    }
                    .store(in: &self.disposeBag)
            }
            .store(in: &self.disposeBag)
        
        title = L10n.Scene.ConfirmEmail.title
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        
        configureMargin()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let nowIn60Seconds = Date().addingTimeInterval(60)
        let boldFont = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .bold))
        let regularFont = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular))
        let digitFont = UIFontMetrics(forTextStyle: .body).scaledFont(for: .monospacedDigitSystemFont(ofSize: 15, weight: .bold))
        
        let timer = Timer(timeInterval: 1.0, repeats: true) { [weak self] in 
            guard Date() < nowIn60Seconds else {
                self?.resendEmailButton.isEnabled = true

                var configuration = self?.resendEmailButton.configuration

                let boldResendString = AttributedString(L10n.Scene.ConfirmEmail.DidntGetLink.resendNow, attributes: .init([.font: boldFont]))
                var attributedTitle = AttributedString(L10n.Scene.ConfirmEmail.DidntGetLink.prefix, attributes: .init([.font: regularFont]))

                attributedTitle.append(AttributedString(" "))
                attributedTitle.append(boldResendString)

                configuration?.attributedTitle = attributedTitle
                self?.resendEmailButton.configuration = configuration
                self?.resendEmailButton.setNeedsUpdateConfiguration()

                $0.invalidate()
                return
            }

            var configuration = self?.resendEmailButton.configuration

            let boldResendString = AttributedString(L10n.Scene.ConfirmEmail.DidntGetLink.resendIn(Int(nowIn60Seconds.timeIntervalSinceNow) + 1), attributes: .init([.font: digitFont]))
            var attributedTitle = AttributedString(L10n.Scene.ConfirmEmail.DidntGetLink.prefix, attributes: .init([.font: regularFont]))

            attributedTitle.append(AttributedString(" "))
            attributedTitle.append(boldResendString)

            configuration?.attributedTitle = attributedTitle
            self?.resendEmailButton.configuration = configuration
            self?.resendEmailButton.setNeedsUpdateConfiguration()
        }

        RunLoop.main.add(timer, forMode: .default)
    }
}

extension MastodonConfirmEmailViewController {
    private func configureMargin() {
        switch traitCollection.horizontalSizeClass {
        case .regular:
            let margin = MastodonConfirmEmailViewController.viewEdgeMargin
            stackView.layoutMargins = UIEdgeInsets(top: 18, left: margin, bottom: 23, right: margin)
        default:
            stackView.layoutMargins = UIEdgeInsets(top: 10, left: 0, bottom: 23, right: 0)
        }
    }
}

extension MastodonConfirmEmailViewController {
    @objc private func resendButtonPressed(_ sender: UIButton) {
        let alertController = UIAlertController(title: L10n.Scene.ConfirmEmail.DontReceiveEmail.title, message: L10n.Scene.ConfirmEmail.DontReceiveEmail.description, preferredStyle: .alert)
        let resendAction = UIAlertAction(title: L10n.Scene.ConfirmEmail.DontReceiveEmail.resendEmail, style: .default) { _ in
            let url = Mastodon.API.resendEmailURL(domain: self.viewModel.authenticateInfo.domain)
            let viewModel = MastodonResendEmailViewModel(resendEmailURL: url, email: self.viewModel.email)
            _ = self.coordinator.present(scene: .mastodonResendEmail(viewModel: viewModel), from: self, transition: .modal(animated: true, completion: nil))
        }
        let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default) { _ in
        }
        alertController.addAction(resendAction)
        alertController.addAction(okAction)
        _ = self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))
    }
}

// MARK: - PanPopableViewController
extension MastodonConfirmEmailViewController: PanPopableViewController {
    var isPanPopable: Bool { false }
}

// MARK: - OnboardingViewControllerAppearance
extension MastodonConfirmEmailViewController: OnboardingViewControllerAppearance { }

#if canImport(SwiftUI) && DEBUG
import SwiftUI

struct MastodonConfirmEmailViewController_Previews: PreviewProvider {
    
    static var controls: some View {
        UIViewControllerPreview {
            let viewController = MastodonConfirmEmailViewController()
            return viewController
        }
        .previewLayout(.fixed(width: 375, height: 800))
    }
    
    static var previews: some View {
            Group {
                controls.colorScheme(.light)
                controls.colorScheme(.dark)
            }
    }
    
}

#endif
