//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
import SignalServiceKit
import UIKit
import SignalUI

// MARK: - RegistrationChangePhoneNumberConfirmationPresenter

protocol RegistrationChangePhoneNumberConfirmationPresenter: AnyObject {
    func confirmChangeNumber(newE164: E164)

    func returnToPhoneNumberEntry()
}

// MARK: - RegistrationChangePhoneNumberConfirmationViewController

class RegistrationChangePhoneNumberConfirmationViewController: OWSViewController, OWSNavigationChildController {

    public var preferredNavigationBarStyle: OWSNavigationBarStyle {
        return .solid
    }

    public var navbarBackgroundColorOverride: UIColor? {
        return view.backgroundColor
    }

    private var state: RegistrationPhoneNumberViewState.ChangeNumberConfirmation
    private weak var presenter: RegistrationChangePhoneNumberConfirmationPresenter?

    private let rootView = UIStackView()

    public init(
        state: RegistrationPhoneNumberViewState.ChangeNumberConfirmation,
        presenter: RegistrationChangePhoneNumberConfirmationPresenter
    ) {
        self.state = state
        self.presenter = presenter
        super.init()
    }

    public func updateState(_ state: RegistrationPhoneNumberViewState.ChangeNumberConfirmation) {
        self.state = state
        updateContents()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        title = OWSLocalizedString("SETTINGS_CHANGE_PHONE_NUMBER_VIEW_TITLE",
                                  comment: "Title for the 'change phone number' views in settings.")

        createContents()
    }

    private var rateLimitErrorTimer: Timer?

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

        updateContents()

        // We only need this timer if the user has been rate limited, but it's simpler to always
        // start it.
        rateLimitErrorTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
            self?.updateContents()
        }
    }

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

        rateLimitErrorTimer?.invalidate()
        rateLimitErrorTimer = nil
    }

    private func createContents() {
        rootView.axis = .vertical
        rootView.alignment = .fill
        rootView.isLayoutMarginsRelativeArrangement = true
        rootView.layoutMargins = UIEdgeInsets(hMargin: 20, vMargin: 0)
        view.addSubview(rootView)
        rootView.autoPinEdge(toSuperviewSafeArea: .leading)
        rootView.autoPinEdge(toSuperviewSafeArea: .trailing)
        rootView.autoPin(toTopLayoutGuideOf: self, withInset: 0)
        rootView.autoPinEdge(.bottom, to: .bottom, of: keyboardLayoutGuideViewSafeArea)

        updateContents()
    }

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

        updateContents()
    }

    private func updateContents() {
        view.backgroundColor = OWSTableViewController2.tableBackgroundColor(isUsingPresentedStyle: true)

        let descriptionFormat = OWSLocalizedString("SETTINGS_CHANGE_PHONE_NUMBER_CONFIRM_DESCRIPTION_FORMAT",
                                                  comment: "Format for the description text in the 'change phone number splash' view. Embeds: {{ %1$@ the old phone number, %2$@ the new phone number }}.")
        let oldPhoneNumberFormatted = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: state.oldE164.stringValue)
        let newPhoneNumberFormatted = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: state.newE164.stringValue)
        let descriptionText = String(
            format: descriptionFormat,
            oldPhoneNumberFormatted,
            newPhoneNumberFormatted
        )
        let descriptionAttributedText = NSMutableAttributedString(string: descriptionText)
        descriptionAttributedText.setAttributes(
            [.foregroundColor: Theme.primaryTextColor],
            forSubstring: oldPhoneNumberFormatted
        )
        descriptionAttributedText.setAttributes(
            [.foregroundColor: Theme.primaryTextColor],
            forSubstring: newPhoneNumberFormatted
        )

        let descriptionLabel = UILabel()
        descriptionLabel.font = .dynamicTypeBody
        descriptionLabel.textColor = Theme.secondaryTextAndIconColor
        descriptionLabel.attributedText = descriptionAttributedText
        descriptionLabel.textAlignment = .center
        descriptionLabel.numberOfLines = 0
        descriptionLabel.lineBreakMode = .byWordWrapping

        let phoneNumberLabel = UILabel()
        phoneNumberLabel.font = .dynamicTypeTitle2.semibold()
        phoneNumberLabel.textColor = Theme.primaryTextColor
        phoneNumberLabel.text = newPhoneNumberFormatted
        phoneNumberLabel.textAlignment = .center
        let phoneNumberStack = UIStackView(arrangedSubviews: [phoneNumberLabel])
        phoneNumberStack.axis = .vertical
        phoneNumberStack.alignment = .center
        phoneNumberStack.isLayoutMarginsRelativeArrangement = true
        phoneNumberStack.layoutMargins = UIEdgeInsets(hMargin: 24, vMargin: 24)
        let phoneNumberBackground = phoneNumberStack.addBackgroundView(withBackgroundColor: Theme.backgroundColor)
        phoneNumberBackground.layer.cornerRadius = 10

        let continueButton = OWSFlatButton.button(title: OWSLocalizedString("SETTINGS_CHANGE_PHONE_NUMBER_CONFIRM_BUTTON",
                                                                           comment: "Label for the 'confirm change phone number' button in the 'change phone number' views."),
                                                  font: UIFont.dynamicTypeBody.semibold(),
                                                  titleColor: .ows_white,
                                                  backgroundColor: .ows_accentBlue,
                                                  target: self,
                                                  selector: #selector(didTapContinue))
        continueButton.autoSetHeightUsingFont()
        continueButton.cornerRadius = 8
        continueButton.setEnabled(state.rateLimitedError?.canSubmit(e164: self.state.newE164, dateProvider: Date.provider) ?? true)

        let editButton = OWSFlatButton.button(title: OWSLocalizedString("SETTINGS_CHANGE_PHONE_NUMBER_BACK_TO_EDIT_BUTTON",
                                                                         comment: "Label for the 'edit phone number' button in the 'change phone number' views."),
                                                font: UIFont.dynamicTypeBody,
                                                titleColor: .ows_accentBlue,
                                                backgroundColor: .clear,
                                                target: self,
                                                selector: #selector(didTapEdit))
        editButton.autoSetHeightUsingFont()
        editButton.cornerRadius = 8

        rootView.removeAllSubviews()
        rootView.addArrangedSubviews([
            UIView.spacer(withHeight: 24),
            descriptionLabel,
            UIView.spacer(withHeight: 20),
            phoneNumberStack
        ])

        if let warningLabelText = state.rateLimitedError?.warningLabelText(e164: self.state.newE164, dateProvider: Date.provider) {
            let warningLabel = UILabel()
            warningLabel.textColor = .ows_accentRed
            warningLabel.numberOfLines = 0
            warningLabel.font = UIFont.dynamicTypeSubheadlineClamped
            warningLabel.accessibilityIdentifier = "registration.phonenumber.validationWarningLabel"
            warningLabel.text = warningLabelText

            rootView.addArrangedSubview(UIView.spacer(withHeight: 12))
            rootView.addArrangedSubview(warningLabel)
        }

        rootView.addArrangedSubviews([
            UIView.vStretchingSpacer(),
            continueButton,
            UIView.spacer(withHeight: 20),
            editButton
        ])
    }

    @objc
    private func didTapEdit(_ sender: UIButton) {
        AssertIsOnMainThread()

        presenter?.returnToPhoneNumberEntry()
    }

    @objc
    private func didTapContinue(_ sender: UIButton) {
        AssertIsOnMainThread()

        guard state.rateLimitedError?.canSubmit(e164: self.state.newE164, dateProvider: Date.provider) != false else {
            return
        }

        presenter?.confirmChangeNumber(newE164: state.newE164)
    }
}
