import PhoneNumberKit
import SwiftUI
import UIKit

// Wrapper around https://github.com/marmelroy/PhoneNumberKit for SwiftUI
public struct PhoneNumberField: UIViewRepresentable {
    @Binding var text: String
    @Binding var countryCodeBehavior: CountryCodeEntryMode

    private let textField: SunoCustomizedPhoneNumberField
    private let font: UIFont?
    private let minimumFontSize: CGFloat
    private let textColor: UIColor?

    public init(
        text: Binding<String>,
        countryCodeBehavior: Binding<CountryCodeEntryMode>,
        onEmptyBackspace: @escaping () -> Void,
        font: UIFont? = TypographyV1.headline2.neueMontrealMedium().uiFont!,
        minimumFontSize: CGFloat = 18,
        textColor: UIColor? = UIColor.SemanticV1.textPrimary
    ) {
        _text = text
        _countryCodeBehavior = countryCodeBehavior
        self.font = font
        self.minimumFontSize = minimumFontSize
        self.textColor = textColor
        self.textField = SunoCustomizedPhoneNumberField(countryCodeBehavior: .nonInteractive, onEmptyBackspace: onEmptyBackspace)
    }

    public func makeUIView(context: Context) -> SunoCustomizedPhoneNumberField {
        textField.withExamplePlaceholder = true
        textField.withDefaultPickerUI = true
        textField.withPrefix = false
        textField.maxDigits = 15
        textField.adjustsFontSizeToFitWidth = true
        textField.minimumFontSize = minimumFontSize
        textField.textContentType = .telephoneNumber
        textField.keyboardType = .phonePad
        textField.font = font
        textField.textColor = textColor
        textField.text = text
        textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        textField.withFlag = true
        textField.countryCodeBehavior = self.countryCodeBehavior

        /// from https://app.hex.tech/883a3868-44c8-45f6-aef6-baa783bac922/app/517da055-38b8-47e1-ba9d-9162c48fe3c6/latest
        /// these are our top 5 countries on 2025-04-04
        /// tapping on the flag will take you to a screen with these countries shown at the top
        CountryCodePicker.commonCountryCodes = [
            "US",
            "IN",
            "BR",
            "SG",
            "ID",
        ]

        textField.addTarget(context.coordinator, action: #selector(Coordinator.textViewDidChange), for: .editingChanged)
        textField.delegate = context.coordinator

        return textField
    }

    public func updateUIView(_ textField: SunoCustomizedPhoneNumberField, context _: UIViewRepresentableContext<Self>) {
        /// Leaving this here as a reminder **not** to do this
        /// if the user is editing the text field quickly, there's a delay here and we delete the last digit they enter
        /// The downside here is that we can't write to the text field from our application code in SwiftUI -- but we don't write, we only read the phone number. so it's fine in this case
//        DispatchQueue.main.async {
//            textField.text = text
//        }

        let requiresCountryCodeAdjustment = textField.countryCodeBehavior == .nonInteractive && self.countryCodeBehavior == .interactive
        textField.countryCodeBehavior = self.countryCodeBehavior
        if requiresCountryCodeAdjustment {
            /// When we switch from nonInteractive to interactive, we switch the textField to show the country code in the field, instead of in it's prefix label
            /// when that happens, we need to insert the remainder of the country code prefix into the textField's text
            if let currentPrefixText = self.textField.prefixLabel.text {
                textField.text = String(currentPrefixText.dropLast())
            }
        }
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator(text: $text)
    }

    // MARK: - Coordinator

    public class Coordinator: NSObject, UITextFieldDelegate {
        let text: Binding<String>

        init(text: Binding<String>) {
            self.text = text
        }

        @objc public func textViewDidChange(_ textField: UITextField) {
            DispatchQueue.main.async { [weak self] in
                self?.text.wrappedValue = textField.text ?? ""
            }
        }
    }
}

public enum CountryCodeEntryMode {
    case nonInteractive
    case interactive
}

public class SunoCustomizedPhoneNumberField: PhoneNumberKit.PhoneNumberTextField {
    let prefixLabel = UILabel().with {
        $0.text = ""
        $0.font = TypographyV1.headline2.neueMontrealMedium().uiFont!
    }

    lazy var leftButtonStack = UIStackView(arrangedSubviews: [flagButton, prefixLabel])

    private let onEmptyBackspace: () -> Void
    fileprivate var countryCodeBehavior: CountryCodeEntryMode {
        didSet {
            switch countryCodeBehavior {
            case .nonInteractive:
                self.leftView = leftButtonStack
                self.withPrefix = false

            case .interactive:
                self.leftView = flagButton
                self.withPrefix = true
            }
        }
    }

    fileprivate init(
        countryCodeBehavior: CountryCodeEntryMode,
        onEmptyBackspace: @escaping () -> Void
    ) {
        self.countryCodeBehavior = countryCodeBehavior
        self.onEmptyBackspace = onEmptyBackspace
        super.init(insets: UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 0), clearButtonPadding: .zero)
    }

    @available(*, unavailable)
    @MainActor required init(coder _: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

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

        /// show image on right of text
        flagButton.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        flagButton.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        flagButton.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

        let chevronImage = UIImage(systemName: "chevron.down")?.withConfiguration(
            UIImage.SymbolConfiguration(pointSize: 18, weight: .medium)
        )
        self.flagButton.setImage(chevronImage, for: .normal)
        self.flagButton.tintColor = UIColor.SemanticV1.textPrimary
    }

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

        // we show our own placeholder in the nonInteractive country code state
        guard let countryCode = self.utility.metadata(for: self.currentRegion) else {
            return
        }
        self.prefixLabel.text = "+\(countryCode.countryCode)"
    }

    override public func deleteBackward() {
        super.deleteBackward()
        if (self.text ?? "").isEmpty {
            self.onEmptyBackspace()
        }
    }
}

#Preview {
    @Previewable @State var text: String = ""
    @Previewable @State var countryCodeBehavior = CountryCodeEntryMode.interactive

    PhoneNumberField(text: $text, countryCodeBehavior: $countryCodeBehavior, onEmptyBackspace: {
        countryCodeBehavior = .interactive
    })
}
