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

import SignalServiceKit
import SignalUI

protocol RegistrationPhoneNumberDiscoverabilityPresenter: AnyObject {
    func setPhoneNumberDiscoverability(_ phoneNumberDiscoverability: PhoneNumberDiscoverability)
    var presentedAsModal: Bool { get }
}

public struct RegistrationPhoneNumberDiscoverabilityState: Equatable {
    let e164: E164
    let phoneNumberDiscoverability: PhoneNumberDiscoverability
}

class RegistrationPhoneNumberDiscoverabilityViewController: OWSViewController {

    private enum Constants {
        static let continueButtonInsets: UIEdgeInsets = .init(
                 top: 16.0,
                 leading: 36.0,
                 bottom: 48,
                 trailing: 36.0
             )
             static let continueButtonEdgeInsets: UIEdgeInsets = .init(
                 hMargin: 0,
                 vMargin: 16
             )
    }

    private let state: RegistrationPhoneNumberDiscoverabilityState
    private weak var presenter: RegistrationPhoneNumberDiscoverabilityPresenter?

    public init(
        state: RegistrationPhoneNumberDiscoverabilityState,
        presenter: RegistrationPhoneNumberDiscoverabilityPresenter
    ) {
        self.state = state
        self.presenter = presenter
        self.phoneNumberDiscoverability = state.phoneNumberDiscoverability
        super.init()
        render()
    }

    @available(*, unavailable)
    public override init() {
        owsFail("This should not be called")
    }

    // MARK: State

    private var phoneNumberDiscoverability: PhoneNumberDiscoverability {
        didSet { render() }
    }

    // MARK: Rendering

    private lazy var titleLabel: UILabel = {
        let result = UILabel.titleLabelForRegistration(text: OWSLocalizedString(
            "ONBOARDING_PHONE_NUMBER_DISCOVERABILITY_TITLE",
            comment: "Title of the 'onboarding phone number discoverability' view."
        ))
        result.accessibilityIdentifier = "registration.phoneNumberDiscoverability.titleLabel"
        return result
    }()

    private lazy var explanationLabel: UILabel = {
        let formattedPhoneNumber = state.e164.stringValue
        let explanationTextFormat = OWSLocalizedString(
            "ONBOARDING_PHONE_NUMBER_DISCOVERABILITY_EXPLANATION_FORMAT",
            comment: "Explanation of the 'onboarding phone number discoverability' view. Embeds {user phone number}"
        )

        let result = UILabel.explanationLabelForRegistration(
            text: String(format: explanationTextFormat, formattedPhoneNumber)
        )
        result.accessibilityIdentifier = "registration.phoneNumberDiscoverability.explanationLabel"

        return result
    }()

    private lazy var everybodyButton: ButtonRow = createButtonForDiscoverability(.everybody)
    private lazy var nobodyButton: ButtonRow = createButtonForDiscoverability(.nobody)

    private func createButtonForDiscoverability(_ phoneNumberDiscoverability: PhoneNumberDiscoverability) -> ButtonRow {
        let result = ButtonRow(title: phoneNumberDiscoverability.nameForDiscoverability)
        result.handler = { [weak self] _ in
            self?.phoneNumberDiscoverability = phoneNumberDiscoverability
        }
        return result
    }

    private lazy var selectionDescriptionLabel: UILabel = {
        let result = UILabel()
        result.font = .dynamicTypeCaption1Clamped
        result.numberOfLines = 0
        result.lineBreakMode = .byWordWrapping
        return result
    }()

    private lazy var nextBarButton = UIBarButtonItem(
        title: CommonStrings.nextButton,
        style: .done,
        target: self,
        action: #selector(didTapSave),
        accessibilityIdentifier: "registration.phoneNumberDiscoverability.nextButton"
    )

    private lazy var continueButton: UIView = {
        let footerView = UIView()
        let continueButton = OWSFlatButton.insetButton(
            title: CommonStrings.continueButton,
            font: UIFont.dynamicTypeBodyClamped.semibold(),
            titleColor: .white,
            backgroundColor: .ows_accentBlue,
            target: self,
            selector: #selector(didTapSave))
        continueButton.accessibilityIdentifier = "registration.phoneNumberDiscoverability.saveButton"

        footerView.addSubview(continueButton)

        continueButton.contentEdgeInsets = Constants.continueButtonEdgeInsets
        continueButton.autoPinEdgesToSuperviewEdges(with: Constants.continueButtonInsets)

        return footerView
    }()

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

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

    private func initialRender() {
        navigationItem.setHidesBackButton(true, animated: false)
        if !(presenter?.presentedAsModal ?? true) {
            navigationItem.rightBarButtonItem = nextBarButton
        }

        let descriptionLabelContainer = UIView()
        descriptionLabelContainer.addSubview(selectionDescriptionLabel)
        selectionDescriptionLabel.autoPinEdgesToSuperviewMargins()

        var stackSubviews = [
            titleLabel,
            .spacer(withHeight: 16),
            explanationLabel,
            .spacer(withHeight: 24),
            everybodyButton,
            nobodyButton,
            .spacer(withHeight: 16),
            descriptionLabelContainer,
            .vStretchingSpacer(minHeight: 16)
        ]

        if presenter?.presentedAsModal ?? false {
            stackSubviews.append(contentsOf: [
                continueButton,
                .spacer(withHeight: 16)
            ])
        }

        let stackView = UIStackView(arrangedSubviews: stackSubviews)
        stackView.axis = .vertical
        view.addSubview(stackView)
        stackView.autoPinEdgesToSuperviewMargins()

        render()
    }

    private func render() {
        everybodyButton.isSelected = phoneNumberDiscoverability == .everybody
        everybodyButton.render()

        nobodyButton.isSelected = phoneNumberDiscoverability == .nobody
        nobodyButton.render()

        selectionDescriptionLabel.text = phoneNumberDiscoverability.descriptionForDiscoverability

        view.backgroundColor = Theme.backgroundColor
        continueButton.tintColor = Theme.accentBlueColor
        titleLabel.textColor = .colorForRegistrationTitleLabel
        explanationLabel.textColor = .colorForRegistrationExplanationLabel
        selectionDescriptionLabel.textColor = .colorForRegistrationExplanationLabel
    }

    // MARK: Events

    @objc
    private func didTapSave() {
        presenter?.setPhoneNumberDiscoverability(phoneNumberDiscoverability)
    }
}

// MARK: - ButtonRow

private class ButtonRow: UIButton {
    var handler: ((ButtonRow) -> Void)?

    private let selectedImageView = UIImageView()

    static let vInset: CGFloat = 11
    static var hInset: CGFloat { UIDevice.current.isPlusSizePhone ? 20 : 16 }

    override var isSelected: Bool {
        didSet {
            selectedImageView.isHidden = !isSelected
        }
    }

    private lazy var buttonLabel: UILabel = UILabel()

    private lazy var divider: UIView = UIView()

    init(title: String) {
        super.init(frame: .zero)

        addTarget(self, action: #selector(didTap), for: .touchUpInside)

        buttonLabel.text = title

        selectedImageView.isHidden = true
        selectedImageView.contentMode = .scaleAspectFit
        selectedImageView.autoSetDimension(.width, toSize: 24)

        let stackView = UIStackView(arrangedSubviews: [buttonLabel, .hStretchingSpacer(), selectedImageView])
        stackView.isUserInteractionEnabled = false
        stackView.axis = .horizontal
        stackView.spacing = 8
        stackView.isLayoutMarginsRelativeArrangement = true
        stackView.layoutMargins = UIEdgeInsets(
            top: Self.vInset,
            leading: Self.hInset,
            bottom: Self.vInset,
            trailing: Self.hInset
        )

        addSubview(stackView)
        stackView.autoPinEdgesToSuperviewEdges()
        stackView.autoSetDimension(.height, toSize: 44, relation: .greaterThanOrEqual)

        addSubview(divider)
        divider.autoSetDimension(.height, toSize: .hairlineWidth)
        divider.autoPinEdge(toSuperviewEdge: .trailing)
        divider.autoPinEdge(toSuperviewEdge: .bottom)
        divider.autoPinEdge(toSuperviewEdge: .leading, withInset: Self.hInset)

        render()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public func render() {
        setBackgroundImage(UIImage.image(color: Theme.cellSelectedColor), for: .highlighted)
        setBackgroundImage(UIImage.image(color: Theme.backgroundColor), for: .normal)

        buttonLabel.textColor = Theme.primaryTextColor
        buttonLabel.font = .dynamicTypeBodyClamped

        divider.backgroundColor = .ows_middleGray

        selectedImageView.setTemplateImage(Theme.iconImage(.checkmark), tintColor: Theme.primaryIconColor)
    }

    @objc
    func didTap() {
        handler?(self)
    }
}
