import HUD
import UIKit
import Models
import Shared
import Combine
import Defaults
import InputField
import Integration
import CombineSchedulers
import DependencyInjection

struct OnboardingEmailConfirmationViewState: Equatable {
    var input: String = ""
    var status: InputField.ValidationStatus = .unknown(nil)
    var resendDebouncer: Int = 0
}

final class OnboardingEmailConfirmationViewModel {
    @Dependency private var session: SessionType

    var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() }
    private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none)

    var completionPublisher: AnyPublisher<AttributeConfirmation, Never> { completionRelay.eraseToAnyPublisher() }
    private let completionRelay = PassthroughSubject<AttributeConfirmation, Never>()

    var timer: Timer?
    let confirmation: AttributeConfirmation

    var state: AnyPublisher<OnboardingEmailConfirmationViewState, Never> { stateRelay.eraseToAnyPublisher() }
    private let stateRelay = CurrentValueSubject<OnboardingEmailConfirmationViewState, Never>(.init())

    var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler()

    init(_ confirmation: AttributeConfirmation) {
        self.confirmation = confirmation
        didTapResend()
    }

    func didInput(_ string: String) {
        stateRelay.value.input = string
        validate()
    }

    func didTapResend() {
        guard stateRelay.value.resendDebouncer == 0 else { return }

        stateRelay.value.resendDebouncer = 60

        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {  [weak self] in
            guard let self = self, self.stateRelay.value.resendDebouncer > 0 else {
                $0.invalidate()
                return
            }

            self.stateRelay.value.resendDebouncer -= 1
        }
    }

    func didTapNext() {
        hudRelay.send(.on(nil))

        backgroundScheduler.schedule { [weak self] in
            guard let self = self else { return }

            do {
                try self.session.confirm(
                    code: self.stateRelay.value.input,
                    confirmation: self.confirmation
                )

                self.timer?.invalidate()
                self.hudRelay.send(.none)
                self.completionRelay.send(self.confirmation)
            } catch {
                self.hudRelay.send(.error(.init(with: error)))
            }
        }
    }

    private func validate() {
        switch Validator.code.validate(stateRelay.value.input) {
        case .success:
            stateRelay.value.status = .valid(nil)
        case .failure(let error):
            stateRelay.value.status = .invalid(error)
        }
    }
}