//
//  RealNameAuthViewController.swift
//  suixinkan
//

import PhotosUI
import SnapKit
import UIKit

/// 实名认证页面，对齐 Android 两步提交与审核状态的完整视觉和交互。
final class RealNameAuthViewController: BaseViewController {
    private let viewModel: RealNameAuthViewModel
    private let profileAPI = NetworkServices.shared.profileAPI
    private let ossUploadService = NetworkServices.shared.ossUploadService

    private let rootStack = UIStackView()
    private let statusView = RealNameAuditStatusView()
    private let scrollView = UIScrollView()
    private let contentStack = UIStackView()
    private let formStack = UIStackView()
    private let stepOneStack = UIStackView()
    private let stepTwoStack = UIStackView()

    private let nationalEmblemUploadView = RealNameIDCardUploadView(title: "身份证国徽面")
    private let portraitUploadView = RealNameIDCardUploadView(title: "身份证人像面")
    private let realNameField = RealNameLabeledTextField(title: "姓名", placeholder: "请输入真实名称")
    private let idCardField = RealNameLabeledTextField(title: "身份证号码", placeholder: "请输入18位身份证号码")
    private let validitySelectionView = RealNameValiditySelectionView()
    private let startDateButton = RealNameDateButton(placeholder: "起始日期")
    private let endDateButton = RealNameDateButton(placeholder: "截至日期")

    private let readonlyNameField = RealNameReadOnlyField(title: "姓名")
    private let readonlyIDField = RealNameReadOnlyField(title: "身份证号码")
    private let verificationStack = UIStackView()
    private let phoneLabel = UILabel()
    private let smsCodeField = RealNameBorderTextField(placeholder: "请输入验证码")
    private let sendCodeButton = UIButton(type: .system)

    private let actionButton = AppButton(title: "下一步")
    private let agreementRow = AgreementRowView()
    private let agreementContainer = UIView()

    private var pickingSide: RealNameImageSide = .front

    /// 使用可选审核信息创建页面；无信息时进入首次认证模式。
    init(info: RealNameInfo? = nil) {
        viewModel = RealNameAuthViewModel(info: info)
        super.init(nibName: nil, bundle: nil)
    }

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

    override func setupNavigationBar() {
        let titleLabel = UILabel()
        titleLabel.text = "实名认证"
        titleLabel.font = .systemFont(ofSize: 18, weight: .medium)
        titleLabel.textColor = AppColor.text333
        navigationItem.titleView = titleLabel
        let backImage = UIImage(systemName: "arrow.left")?.withConfiguration(
            UIImage.SymbolConfiguration(pointSize: 18, weight: .medium)
        )
        navigationItem.leftBarButtonItem = UIBarButtonItem(
            image: backImage,
            style: .plain,
            target: self,
            action: #selector(backTapped)
        )
        navigationItem.leftBarButtonItem?.tintColor = AppColor.text333
    }

    override func setupUI() {
        view.backgroundColor = UIColor(hex: 0xF9FAFB)
        setupRootLayout()
        setupFormCard()
        setupSupplementaryCards()
        setupInputs()
        applyViewModel()
    }

    override func setupConstraints() {
        rootStack.snp.makeConstraints { make in
            make.edges.equalTo(view.safeAreaLayoutGuide)
        }
        contentStack.snp.makeConstraints { make in
            make.edges.equalTo(scrollView.contentLayoutGuide).inset(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))
            make.width.equalTo(scrollView.frameLayoutGuide).offset(-32)
        }
    }

    override func bindActions() {
        viewModel.onStateChange = { [weak self] in
            Task { @MainActor in self?.applyViewModel() }
        }

        realNameField.textField.addTarget(self, action: #selector(realNameChanged), for: .editingChanged)
        idCardField.textField.addTarget(self, action: #selector(idCardChanged), for: .editingChanged)
        smsCodeField.addTarget(self, action: #selector(smsCodeChanged), for: .editingChanged)
        actionButton.addTarget(self, action: #selector(actionTapped), for: .touchUpInside)
        sendCodeButton.addTarget(self, action: #selector(sendCodeTapped), for: .touchUpInside)

        nationalEmblemUploadView.onSelect = { [weak self] in self?.pickImage(side: .back) }
        nationalEmblemUploadView.onDelete = { [weak self] in self?.viewModel.deleteIdentityImage(side: .back) }
        portraitUploadView.onSelect = { [weak self] in self?.pickImage(side: .front) }
        portraitUploadView.onDelete = { [weak self] in self?.viewModel.deleteIdentityImage(side: .front) }
        validitySelectionView.onToggle = { [weak self] in
            guard let self else { return }
            self.viewModel.updateLongValid(!self.viewModel.isLongValid)
        }
        startDateButton.onTap = { [weak self] in self?.presentDatePicker(for: .start) }
        endDateButton.onTap = { [weak self] in self?.presentDatePicker(for: .end) }
        agreementRow.onCheckedChange = { [weak self] in self?.viewModel.toggleAgreement() }
        agreementRow.onUserAgreementTap = { [weak self] in
            self?.openAgreement(title: "用户协议", url: AppAgreementURLs.walletUserNotice)
        }
        agreementRow.onPrivacyPolicyTap = { [weak self] in
            self?.openAgreement(title: "隐私政策", url: AppAgreementURLs.walletPrivacyPolicy)
        }
    }

    private func setupRootLayout() {
        rootStack.axis = .vertical
        rootStack.spacing = 0
        scrollView.alwaysBounceVertical = true
        contentStack.axis = .vertical
        contentStack.spacing = 8

        view.addSubview(rootStack)
        rootStack.addArrangedSubview(statusView)
        rootStack.addArrangedSubview(scrollView)
        scrollView.addSubview(contentStack)
    }

    private func setupFormCard() {
        formStack.axis = .vertical
        formStack.spacing = 8
        stepOneStack.axis = .vertical
        stepOneStack.spacing = 8
        stepTwoStack.axis = .vertical
        stepTwoStack.spacing = 8

        stepOneStack.addArrangedSubview(nationalEmblemUploadView)
        stepOneStack.addArrangedSubview(portraitUploadView)
        stepOneStack.addArrangedSubview(realNameField)
        stepOneStack.addArrangedSubview(idCardField)
        stepOneStack.addArrangedSubview(validitySelectionView)

        let dateRow = UIStackView(arrangedSubviews: [startDateButton, endDateButton])
        dateRow.axis = .horizontal
        dateRow.spacing = 13
        dateRow.distribution = .fillEqually
        stepOneStack.addArrangedSubview(dateRow)

        verificationStack.axis = .vertical
        verificationStack.spacing = 8
        phoneLabel.font = .systemFont(ofSize: 12, weight: .medium)
        phoneLabel.textColor = AppColor.text666

        let codeRow = UIStackView(arrangedSubviews: [smsCodeField, sendCodeButton])
        codeRow.axis = .horizontal
        codeRow.alignment = .fill
        codeRow.spacing = 8
        sendCodeButton.snp.makeConstraints { make in make.width.equalTo(100) }
        verificationStack.addArrangedSubview(phoneLabel)
        verificationStack.addArrangedSubview(codeRow)

        stepTwoStack.addArrangedSubview(readonlyNameField)
        stepTwoStack.addArrangedSubview(readonlyIDField)
        stepTwoStack.addArrangedSubview(verificationStack)

        let actionContainer = UIView()
        actionContainer.addSubview(actionButton)
        actionButton.titleLabel?.font = .systemFont(ofSize: 17)
        actionButton.snp.makeConstraints { make in
            make.top.bottom.equalToSuperview()
            make.leading.trailing.equalToSuperview().inset(4)
        }

        agreementContainer.addSubview(agreementRow)
        agreementRow.snp.makeConstraints { make in
            make.top.bottom.equalToSuperview().inset(4)
            make.leading.trailing.equalToSuperview().inset(4)
        }

        formStack.addArrangedSubview(stepOneStack)
        formStack.addArrangedSubview(stepTwoStack)
        formStack.setCustomSpacing(12, after: stepTwoStack)
        formStack.addArrangedSubview(actionContainer)
        formStack.addArrangedSubview(agreementContainer)

        contentStack.addArrangedSubview(makeCard(containing: formStack, insets: UIEdgeInsets(top: 16, left: 16, bottom: 10, right: 16)))
    }

    private func setupSupplementaryCards() {
        let privileges = UIStackView()
        privileges.axis = .vertical
        privileges.spacing = 16
        privileges.addArrangedSubview(makeHeading("实名认证特权"))
        privileges.addArrangedSubview(
            RealNamePrivilegeItemView(
                imageName: "ic_accept_orders",
                title: "开启接单权限",
                detail: "完成实名认证后可立即接单,实名状态对游客可见"
            )
        )
        privileges.addArrangedSubview(
            RealNamePrivilegeItemView(
                imageName: "ic_marketing",
                title: "加入营销群",
                detail: "专业摄影师交流群,获取更多流量与技术支持"
            )
        )
        privileges.addArrangedSubview(
            RealNamePrivilegeItemView(
                imageName: "ic_area_authority",
                title: "景区选择权限",
                detail: "可自主选择运营景区,获得独家运营资源"
            )
        )
        contentStack.addArrangedSubview(makeCard(containing: privileges, insets: UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)))

        let hints = UIStackView()
        hints.axis = .vertical
        hints.spacing = 4
        hints.addArrangedSubview(makeHeading("温馨提示:"))
        hints.setCustomSpacing(8, after: hints.arrangedSubviews[0])
        [
            "• 请确保填写的信息真实有效",
            "• 身份信息仅用于实名认证,我们将严格保护您的隐私",
            "• 如有疑问请联系客服",
        ].forEach { text in
            let label = UILabel()
            label.text = text
            label.font = .systemFont(ofSize: 14)
            label.textColor = AppColor.text666
            label.numberOfLines = 0
            hints.addArrangedSubview(label)
        }
        contentStack.addArrangedSubview(makeCard(containing: hints, insets: UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)))
    }

    private func setupInputs() {
        realNameField.textField.textContentType = .name
        realNameField.textField.returnKeyType = .next
        idCardField.textField.keyboardType = .asciiCapable
        idCardField.textField.returnKeyType = .done
        smsCodeField.keyboardType = .numberPad

        sendCodeButton.backgroundColor = AppColor.primary
        sendCodeButton.layer.cornerRadius = 10
        sendCodeButton.clipsToBounds = true
        sendCodeButton.titleLabel?.font = .systemFont(ofSize: 14, weight: .medium)
        sendCodeButton.setTitleColor(.white, for: .normal)
        sendCodeButton.setTitleColor(UIColor.white.withAlphaComponent(0.7), for: .disabled)
        sendCodeButton.snp.makeConstraints { make in make.height.equalTo(46) }
    }

    private func applyViewModel() {
        let readOnly = viewModel.mode.isReadOnly
        statusView.isHidden = viewModel.info == nil
        if let info = viewModel.info {
            statusView.configure(info: info)
        }

        stepOneStack.isHidden = viewModel.currentStep != .identity
        stepTwoStack.isHidden = viewModel.currentStep != .verification

        if realNameField.textField.text != viewModel.realName {
            realNameField.textField.text = viewModel.realName
        }
        if idCardField.textField.text != viewModel.idCardNo {
            idCardField.textField.text = viewModel.idCardNo
        }
        realNameField.setReadOnly(readOnly)
        idCardField.setReadOnly(readOnly)

        nationalEmblemUploadView.configure(
            imageData: viewModel.backPreviewImageData,
            url: viewModel.backUrl,
            uploading: viewModel.isBackUploading,
            progress: viewModel.backUploadProgress,
            canEdit: viewModel.mode.isEditable
        )
        portraitUploadView.configure(
            imageData: viewModel.frontPreviewImageData,
            url: viewModel.frontUrl,
            uploading: viewModel.isFrontUploading,
            progress: viewModel.frontUploadProgress,
            canEdit: viewModel.mode.isEditable
        )

        validitySelectionView.configure(isLongValid: viewModel.isLongValid, enabled: viewModel.mode.isEditable)
        startDateButton.configure(date: viewModel.startDate, readOnly: readOnly, enabled: viewModel.mode.isEditable)
        endDateButton.configure(
            date: viewModel.endDate,
            replacementText: viewModel.isLongValid ? "长期有效" : nil,
            readOnly: readOnly || viewModel.isLongValid,
            enabled: viewModel.mode.isEditable && !viewModel.isLongValid
        )

        readonlyNameField.setValue(viewModel.realName)
        readonlyIDField.setValue(viewModel.idCardNo)
        phoneLabel.text = "验证码将发送至：\(AppStore.shared.session.phone)"
        verificationStack.isHidden = readOnly
        if smsCodeField.text != viewModel.smsCode {
            smsCodeField.text = viewModel.smsCode
        }

        let codeTitle = viewModel.otpCountdown > 0 ? "\(viewModel.otpCountdown)秒" : "获取验证码"
        sendCodeButton.setTitle(codeTitle, for: .normal)
        sendCodeButton.setTitle(codeTitle, for: .disabled)
        sendCodeButton.isEnabled = viewModel.canRequestCode
        sendCodeButton.backgroundColor = viewModel.canRequestCode
            ? AppColor.primary
            : (viewModel.otpCountdown > 0 ? AppColor.primary.withAlphaComponent(0.7) : UIColor(hex: 0xE5E7EB))

        switch viewModel.currentStep {
        case .identity:
            actionButton.setTitle("下一步", for: .normal)
            actionButton.isEnabled = readOnly || viewModel.canGoNextStep
        case .verification:
            actionButton.setTitle("确认提交", for: .normal)
            actionButton.isEnabled = viewModel.canSubmit
        }
        agreementContainer.isHidden = readOnly
        agreementRow.isChecked = viewModel.isAgreed
    }

    @objc private func backTapped() {
        if viewModel.currentStep == .verification {
            viewModel.backToIdentityStep()
        } else {
            navigationController?.popViewController(animated: true)
        }
    }

    @objc private func realNameChanged() {
        viewModel.updateRealName(realNameField.textField.text ?? "")
    }

    @objc private func idCardChanged() {
        viewModel.updateIdCardNo(idCardField.textField.text ?? "")
    }

    @objc private func smsCodeChanged() {
        viewModel.updateSmsCode(smsCodeField.text ?? "")
    }

    @objc private func actionTapped() {
        switch viewModel.currentStep {
        case .identity:
            if let message = viewModel.goToVerificationStep() {
                showToast(message)
            }
        case .verification:
            Task { await submit() }
        }
    }

    @objc private func sendCodeTapped() {
        Task {
            showLoading()
            defer { hideLoading() }
            do {
                try await viewModel.sendCode(api: profileAPI)
                showToast(viewModel.statusMessage ?? "验证码发送成功")
            } catch {
                showToast("验证码发送失败，请稍后重试")
            }
        }
    }

    private func submit() async {
        showLoading()
        defer { hideLoading() }
        do {
            try await viewModel.submit(api: profileAPI)
            showToast(viewModel.statusMessage ?? "认证成功")
            try? await Task.sleep(for: .milliseconds(350))
            navigationController?.popViewController(animated: true)
        } catch {
            showToast(error.localizedDescription)
        }
    }

    private func pickImage(side: RealNameImageSide) {
        guard viewModel.mode.isEditable else { return }
        pickingSide = side
        var configuration = PHPickerConfiguration(photoLibrary: .shared())
        configuration.filter = .images
        configuration.selectionLimit = 1
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        present(picker, animated: true)
    }

    private func presentDatePicker(for field: RealNameDateField) {
        guard viewModel.mode.isEditable else { return }
        let selectedDate = field == .start ? viewModel.startDate : viewModel.endDate
        let controller = RealNameDatePickerViewController(selectedDate: selectedDate)
        controller.onConfirm = { [weak self] date in
            if field == .start {
                self?.viewModel.updateStartDate(date)
            } else {
                self?.viewModel.updateEndDate(date)
            }
        }
        present(controller, animated: false)
    }

    private func openAgreement(title: String, url: URL) {
        navigationController?.pushViewController(AgreementWebViewController(title: title, url: url), animated: true)
    }

    private func makeCard(containing stack: UIStackView, insets: UIEdgeInsets) -> UIView {
        let card = UIView()
        card.backgroundColor = .white
        card.layer.cornerRadius = 12
        card.clipsToBounds = true
        card.addSubview(stack)
        stack.snp.makeConstraints { make in make.edges.equalToSuperview().inset(insets) }
        return card
    }

    private func makeHeading(_ text: String) -> UILabel {
        let label = UILabel()
        label.text = text
        label.font = .systemFont(ofSize: 16, weight: .medium)
        label.textColor = AppColor.text333
        return label
    }
}

extension RealNameAuthViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        guard let provider = results.first?.itemProvider, provider.canLoadObject(ofClass: UIImage.self) else { return }
        provider.loadObject(ofClass: UIImage.self) { [weak self] object, error in
            guard let self else { return }
            if let error {
                Task { @MainActor in self.showToast(error.localizedDescription) }
                return
            }
            guard let image = object as? UIImage, let data = image.jpegData(compressionQuality: 0.95) else { return }
            Task { @MainActor in
                let scenicId = AppStore.shared.session.currentScenicId
                self.showLoading()
                defer { self.hideLoading() }
                do {
                    try await self.viewModel.uploadIdentityImage(
                        data: data,
                        side: self.pickingSide,
                        uploader: self.ossUploadService,
                        scenicId: scenicId
                    )
                } catch {
                    self.showToast(error.localizedDescription)
                }
            }
        }
    }
}

/// 实名认证日期字段类型。
private enum RealNameDateField {
    case start
    case end
}

/// 带标题和边框的实名认证输入框。
private final class RealNameLabeledTextField: UIView {
    let textField = RealNameBorderTextField(placeholder: "")
    private let titleLabel = UILabel()

    init(title: String, placeholder: String) {
        super.init(frame: .zero)
        titleLabel.text = title
        titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
        titleLabel.textColor = .black
        textField.placeholder = placeholder

        let stack = UIStackView(arrangedSubviews: [titleLabel, textField])
        stack.axis = .vertical
        stack.spacing = 8
        addSubview(stack)
        stack.snp.makeConstraints { make in make.edges.equalToSuperview() }
    }

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

    func setReadOnly(_ readOnly: Bool) {
        textField.isEnabled = !readOnly
        textField.backgroundColor = readOnly ? UIColor(hex: 0xEEEEEE) : .white
    }
}

/// Android 边框输入框的 UIKit 实现。
private final class RealNameBorderTextField: UITextField {
    private let horizontalInset: CGFloat = 8

    init(placeholder: String) {
        super.init(frame: .zero)
        self.placeholder = placeholder
        font = .systemFont(ofSize: 14)
        textColor = AppColor.text333
        layer.borderWidth = 1
        layer.borderColor = AppColor.border.cgColor
        layer.cornerRadius = 8
        clipsToBounds = true
        clearButtonMode = .whileEditing
        snp.makeConstraints { make in make.height.equalTo(46) }
    }

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

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        bounds.insetBy(dx: horizontalInset, dy: 0)
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        bounds.insetBy(dx: horizontalInset, dy: 0)
    }

    override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
        bounds.insetBy(dx: horizontalInset, dy: 0)
    }
}

/// 灰底只读字段，对齐 Android 第二步信息展示。
private final class RealNameReadOnlyField: UIView {
    private let valueLabel = UILabel()

    init(title: String) {
        super.init(frame: .zero)
        let titleLabel = UILabel()
        titleLabel.text = title
        titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
        titleLabel.textColor = .black

        let valueBox = UIView()
        valueBox.backgroundColor = UIColor(hex: 0xEEEEEE)
        valueBox.layer.borderWidth = 1
        valueBox.layer.borderColor = UIColor(hex: 0xF4F4F4).cgColor
        valueBox.layer.cornerRadius = 8
        valueLabel.font = .systemFont(ofSize: 14)
        valueLabel.textColor = AppColor.text333
        valueBox.addSubview(valueLabel)
        valueBox.snp.makeConstraints { make in make.height.equalTo(45) }
        valueLabel.snp.makeConstraints { make in make.leading.trailing.equalToSuperview().inset(8); make.centerY.equalToSuperview() }

        let stack = UIStackView(arrangedSubviews: [titleLabel, valueBox])
        stack.axis = .vertical
        stack.spacing = 4
        addSubview(stack)
        stack.snp.makeConstraints { make in make.edges.equalToSuperview() }
    }

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

    func setValue(_ value: String) {
        valueLabel.text = value
    }
}

/// 长期有效选择行。
private final class RealNameValiditySelectionView: UIView {
    private let checkboxButton = UIButton(type: .custom)
    var onToggle: (() -> Void)?

    override init(frame: CGRect) {
        super.init(frame: frame)
        let titleLabel = UILabel()
        titleLabel.text = "有效期"
        titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
        titleLabel.textColor = .black

        checkboxButton.setTitle("  长期有效", for: .normal)
        checkboxButton.setTitleColor(UIColor(hex: 0xB6BECA), for: .normal)
        checkboxButton.titleLabel?.font = .systemFont(ofSize: 14)
        checkboxButton.contentHorizontalAlignment = .right
        checkboxButton.addTarget(self, action: #selector(tapped), for: .touchUpInside)

        let row = UIStackView(arrangedSubviews: [titleLabel, checkboxButton])
        row.axis = .horizontal
        row.alignment = .center
        row.distribution = .equalSpacing
        addSubview(row)
        row.snp.makeConstraints { make in make.edges.equalToSuperview(); make.height.equalTo(28) }
    }

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

    func configure(isLongValid: Bool, enabled: Bool) {
        checkboxButton.setImage(UIImage(named: isLongValid ? "ic_checked" : "ic_unchecked"), for: .normal)
        checkboxButton.isEnabled = enabled
        checkboxButton.alpha = enabled ? 1 : 0.75
    }

    @objc private func tapped() {
        onToggle?()
    }
}

/// 有效期日期按钮。
private final class RealNameDateButton: UIButton {
    private let placeholder: String
    var onTap: (() -> Void)?

    init(placeholder: String) {
        self.placeholder = placeholder
        super.init(frame: .zero)
        layer.borderWidth = 1
        layer.borderColor = AppColor.border.cgColor
        layer.cornerRadius = 4
        titleLabel?.font = .systemFont(ofSize: 14)
        addTarget(self, action: #selector(tapped), for: .touchUpInside)
        snp.makeConstraints { make in make.height.equalTo(45) }
    }

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

    func configure(date: Date?, replacementText: String? = nil, readOnly: Bool, enabled: Bool) {
        let text = replacementText ?? date.map(RealNameDateTextFormatter.string(from:)) ?? placeholder
        setTitle(text, for: .normal)
        setTitleColor(date == nil && replacementText == nil ? UIColor(hex: 0xB6BECA) : AppColor.text333, for: .normal)
        backgroundColor = readOnly ? UIColor(hex: 0xEEEEEE) : .white
        isEnabled = enabled
    }

    @objc private func tapped() {
        onTap?()
    }
}

/// 身份证图片上传区域，负责虚线框、预览、删除和上传遮罩。
private final class RealNameIDCardUploadView: UIView {
    private let titleLabel = UILabel()
    private let canvas = RealNameDashedBorderView()
    private let imageView = UIImageView()
    private let placeholderStack = UIStackView()
    private let placeholderLabel = UILabel()
    private let deleteButton = UIButton(type: .custom)
    private let progressOverlay = UIView()
    private let progressIndicator = UIActivityIndicatorView(style: .medium)
    private let progressLabel = UILabel()
    private var canEdit = false
    private var hasImage = false
    private var loadedURL = ""

    var onSelect: (() -> Void)?
    var onDelete: (() -> Void)?

    init(title: String) {
        super.init(frame: .zero)
        titleLabel.text = title
        titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
        titleLabel.textColor = .black

        imageView.contentMode = .scaleAspectFit
        imageView.clipsToBounds = true
        imageView.isAccessibilityElement = true
        imageView.accessibilityLabel = title

        let plusView = UIImageView(image: UIImage(systemName: "plus"))
        plusView.tintColor = AppColor.primary
        plusView.contentMode = .scaleAspectFit
        plusView.snp.makeConstraints { make in make.size.equalTo(32) }
        placeholderLabel.text = "点击上传图片"
        placeholderLabel.textColor = AppColor.text666
        placeholderLabel.font = .systemFont(ofSize: 12)
        placeholderStack.axis = .vertical
        placeholderStack.alignment = .center
        placeholderStack.spacing = 8
        placeholderStack.addArrangedSubview(plusView)
        placeholderStack.addArrangedSubview(placeholderLabel)

        deleteButton.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        deleteButton.layer.cornerRadius = 10
        deleteButton.setImage(UIImage(systemName: "xmark")?.withConfiguration(UIImage.SymbolConfiguration(pointSize: 10, weight: .medium)), for: .normal)
        deleteButton.tintColor = .white
        deleteButton.addTarget(self, action: #selector(deleteTapped), for: .touchUpInside)

        progressOverlay.backgroundColor = UIColor.black.withAlphaComponent(0.45)
        progressIndicator.color = .white
        progressLabel.font = .systemFont(ofSize: 12, weight: .medium)
        progressLabel.textColor = .white
        let progressStack = UIStackView(arrangedSubviews: [progressIndicator, progressLabel])
        progressStack.axis = .vertical
        progressStack.alignment = .center
        progressStack.spacing = 6

        canvas.addSubview(imageView)
        canvas.addSubview(placeholderStack)
        canvas.addSubview(deleteButton)
        canvas.addSubview(progressOverlay)
        progressOverlay.addSubview(progressStack)
        canvas.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(canvasTapped)))

        let stack = UIStackView(arrangedSubviews: [titleLabel, canvas])
        stack.axis = .vertical
        stack.spacing = 4
        addSubview(stack)
        stack.snp.makeConstraints { make in make.edges.equalToSuperview() }
        canvas.snp.makeConstraints { make in make.height.equalTo(canvas.snp.width).dividedBy(2.1) }
        imageView.snp.makeConstraints { make in make.edges.equalToSuperview() }
        placeholderStack.snp.makeConstraints { make in make.center.equalToSuperview() }
        deleteButton.snp.makeConstraints { make in make.top.trailing.equalToSuperview().inset(4); make.size.equalTo(20) }
        progressOverlay.snp.makeConstraints { make in make.edges.equalToSuperview() }
        progressStack.snp.makeConstraints { make in make.center.equalToSuperview() }
    }

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

    func configure(imageData: Data?, url: String, uploading: Bool, progress: Int, canEdit: Bool) {
        self.canEdit = canEdit
        hasImage = imageData != nil || !url.isEmpty
        if let imageData, let image = UIImage(data: imageData) {
            imageView.image = image
            loadedURL = ""
        } else if !url.isEmpty, loadedURL != url {
            loadedURL = url
            imageView.loadRemoteImage(urlString: url, placeholderColor: .white)
        } else if url.isEmpty {
            loadedURL = ""
            imageView.image = nil
        }

        placeholderStack.isHidden = hasImage
        placeholderLabel.text = canEdit ? "点击上传图片" : "暂无图片"
        deleteButton.isHidden = !hasImage || !canEdit || uploading
        progressOverlay.isHidden = !uploading
        progressLabel.text = "\(progress)%"
        uploading ? progressIndicator.startAnimating() : progressIndicator.stopAnimating()
        canvas.accessibilityTraits = canEdit && !hasImage ? .button : .image
    }

    @objc private func canvasTapped() {
        guard canEdit, !hasImage else { return }
        onSelect?()
    }

    @objc private func deleteTapped() {
        onDelete?()
    }
}

/// 带圆角虚线边框的身份证图片容器。
private final class RealNameDashedBorderView: UIView {
    private let borderLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        layer.cornerRadius = 8
        clipsToBounds = true
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.strokeColor = AppColor.border.cgColor
        borderLayer.lineWidth = 2
        borderLayer.lineDashPattern = [6, 6]
        layer.addSublayer(borderLayer)
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        borderLayer.frame = bounds
        borderLayer.path = UIBezierPath(roundedRect: bounds.insetBy(dx: 1, dy: 1), cornerRadius: 8).cgPath
    }
}

/// 实名认证特权说明行。
private final class RealNamePrivilegeItemView: UIView {
    init(imageName: String, title: String, detail: String) {
        super.init(frame: .zero)
        let iconContainer = UIView()
        iconContainer.backgroundColor = AppColor.primary
        iconContainer.layer.cornerRadius = 12
        iconContainer.snp.makeConstraints { make in make.size.equalTo(24) }
        let iconView = UIImageView(image: UIImage(named: imageName)?.withRenderingMode(.alwaysTemplate))
        iconView.tintColor = .white
        iconView.contentMode = .scaleAspectFit
        iconContainer.addSubview(iconView)
        iconView.snp.makeConstraints { make in make.center.equalToSuperview(); make.size.equalTo(16) }

        let titleLabel = UILabel()
        titleLabel.text = title
        titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
        titleLabel.textColor = AppColor.text333
        let detailLabel = UILabel()
        detailLabel.text = detail
        detailLabel.font = .systemFont(ofSize: 12)
        detailLabel.textColor = AppColor.text666
        detailLabel.numberOfLines = 0

        let textStack = UIStackView(arrangedSubviews: [titleLabel, detailLabel])
        textStack.axis = .vertical
        textStack.spacing = 2
        let row = UIStackView(arrangedSubviews: [iconContainer, textStack])
        row.axis = .horizontal
        row.alignment = .top
        row.spacing = 12
        addSubview(row)
        row.snp.makeConstraints { make in make.edges.equalToSuperview() }
    }

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

/// 审核状态顶部信息条。
private final class RealNameAuditStatusView: UIView {
    private let stack = UIStackView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        stack.axis = .vertical
        stack.spacing = 8
        addSubview(stack)
        stack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 16, left: 20, bottom: 16, right: 20))
        }
    }

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

    func configure(info: RealNameInfo) {
        stack.arrangedSubviews.forEach { view in
            stack.removeArrangedSubview(view)
            view.removeFromSuperview()
        }
        let color: UIColor
        switch info.auditStatus {
        case 2:
            color = AppColor.primary
            backgroundColor = UIColor(hex: 0xEFF6FF)
        case 3:
            color = UIColor(hex: 0xEF4444)
            backgroundColor = UIColor(hex: 0xFFE7E7)
        default:
            color = UIColor(hex: 0xFF7B00)
            backgroundColor = UIColor(hex: 0xFFF0E2)
        }
        let statusText = info.auditStatusText?.nonEmpty ?? Self.fallbackStatusText(for: info.auditStatus)
        stack.addArrangedSubview(makeRow(label: "审核状态", value: statusText, color: color))
        if info.auditStatus == 2 {
            stack.addArrangedSubview(makeRow(label: "审核人：", value: info.auditor?.name ?? "--", color: color))
            stack.addArrangedSubview(makeRow(label: "审核时间：", value: info.auditAt ?? "--", color: color))
        }
        stack.addArrangedSubview(makeRow(label: "审核备注：", value: info.rejectReason ?? "--", color: color))
    }

    private func makeRow(label: String, value: String, color: UIColor) -> UIView {
        let labelView = UILabel()
        labelView.text = label
        labelView.font = .systemFont(ofSize: 14)
        labelView.textColor = color
        let valueView = UILabel()
        valueView.text = value
        valueView.font = .systemFont(ofSize: 14)
        valueView.textColor = color
        valueView.textAlignment = .right
        valueView.numberOfLines = 0
        valueView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        let row = UIStackView(arrangedSubviews: [labelView, valueView])
        row.axis = .horizontal
        row.alignment = .center
        row.distribution = .equalSpacing
        row.spacing = 12
        return row
    }

    private static func fallbackStatusText(for status: Int) -> String {
        switch status {
        case 2: "审核通过"
        case 3: "审核驳回"
        default: "审核中"
        }
    }
}

/// Android 滚轮日期弹窗的 UIKit 实现。
private final class RealNameDatePickerViewController: UIViewController {
    private let datePicker = UIDatePicker()
    private let selectedDate: Date?
    var onConfirm: ((Date) -> Void)?

    init(selectedDate: Date?) {
        self.selectedDate = selectedDate
        super.init(nibName: nil, bundle: nil)
        modalPresentationStyle = .overFullScreen
        modalTransitionStyle = .crossDissolve
    }

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

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .clear

        let dismissButton = UIButton(type: .custom)
        dismissButton.backgroundColor = UIColor.black.withAlphaComponent(0.35)
        dismissButton.addTarget(self, action: #selector(backgroundTapped), for: .touchUpInside)
        view.addSubview(dismissButton)
        dismissButton.snp.makeConstraints { make in make.edges.equalToSuperview() }

        let container = UIView()
        container.backgroundColor = .white
        container.layer.cornerRadius = 10
        container.clipsToBounds = true
        datePicker.datePickerMode = .date
        datePicker.preferredDatePickerStyle = .wheels
        datePicker.locale = Locale(identifier: "zh_CN")
        datePicker.date = selectedDate ?? Date()

        let confirmButton = AppButton(title: "确认")
        confirmButton.titleLabel?.font = .systemFont(ofSize: 17, weight: .medium)
        confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
        confirmButton.snp.remakeConstraints { make in make.height.equalTo(45) }

        let stack = UIStackView(arrangedSubviews: [datePicker, confirmButton])
        stack.axis = .vertical
        stack.spacing = 24
        container.addSubview(stack)
        view.addSubview(container)
        container.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.leading.trailing.equalToSuperview().inset(30)
        }
        stack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 24, left: 15, bottom: 24, right: 15))
        }
    }

    @objc private func confirmTapped() {
        onConfirm?(datePicker.date)
        dismiss(animated: false)
    }

    @objc private func backgroundTapped() {
        dismiss(animated: false)
    }
}

/// 实名认证日期文本格式化工具。
private enum RealNameDateTextFormatter {
    static let formatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .gregorian)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }()

    static func string(from date: Date) -> String {
        formatter.string(from: date)
    }
}

private extension String {
    var nonEmpty: String? {
        isEmpty ? nil : self
    }
}
