import UIKit
import SwiftUI

// MARK: - Wallpaper Definitions

struct WallpaperOption: Identifiable, Equatable {
    let id: String
    let name: String
    let style: WallpaperStyle

    enum WallpaperStyle: Equatable {
        case none
        case image(String)   // Asset catalog image name (supports light/dark appearance)
    }
}

extension WallpaperOption {
    /// Android parity: 3 wallpaper pairs (light/dark) from mobile-android assets.
    /// Each imageset contains light + dark appearance variants.
    /// "ChatWallpaper" = legacy default (wallpaper_light_02 + wallpaper_dark_03).
    static let allOptions: [WallpaperOption] = [
        WallpaperOption(id: "default", name: "Default", style: .image("ChatWallpaper")),
        WallpaperOption(id: "wallpaper_1", name: "Pair 1", style: .image("Wallpaper1")),
        WallpaperOption(id: "wallpaper_2", name: "Pair 2", style: .image("Wallpaper2")),
        WallpaperOption(id: "wallpaper_3", name: "Pair 3", style: .image("Wallpaper3")),
        WallpaperOption(id: "none", name: "None", style: .none),
    ]
}

// MARK: - Theme Mode

enum ThemeMode: String, CaseIterable {
    case dark = "dark"
    case light = "light"
    case system = "system"

    var label: String {
        switch self {
        case .dark: return "Dark"
        case .light: return "Light"
        case .system: return "System"
        }
    }

    var iconName: String {
        switch self {
        case .dark: return "moon.fill"
        case .light: return "sun.max.fill"
        case .system: return "circle.lefthalf.filled"
        }
    }
}

// MARK: - Appearance ViewController

final class AppearanceViewController: UIViewController {

    private let scrollView = UIScrollView()
    private let contentStack = UIStackView()

    // Header
    private let headerBarHeight: CGFloat = 44
    private var backButton: UIControl!
    private let titleLabel = UILabel()

    // Chat preview
    private let previewContainer = UIView()
    private let previewWallpaperView = UIImageView()
    private let incomingBubble = UIView()
    private let outgoingBubble = UIView()

    // Theme section
    private let themeSectionLabel = UILabel()
    private let themeCard = UIView()
    private var themeButtons: [ThemeMode: UIButton] = [:]
    private var themeDividers: [UIView] = []

    // Wallpaper section
    private let wallpaperSectionLabel = UILabel()
    private var wallpaperCells: [String: WallpaperCellView] = [:]

    // State
    private var selectedWallpaperId: String {
        get { UserDefaults.standard.string(forKey: "rosetta_wallpaper_id") ?? "default" }
        set { UserDefaults.standard.set(newValue, forKey: "rosetta_wallpaper_id") }
    }

    private var themeModeRaw: String {
        get { UserDefaults.standard.string(forKey: "rosetta_theme_mode") ?? "system" }
        set { UserDefaults.standard.set(newValue, forKey: "rosetta_theme_mode") }
    }

    private var themeMode: ThemeMode {
        ThemeMode(rawValue: themeModeRaw) ?? .dark
    }

    // MARK: - Init

    init() {
        super.init(nibName: nil, bundle: nil)
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError() }

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor(RosettaColors.Adaptive.background)
        navigationController?.setNavigationBarHidden(true, animated: false)

        setupScrollView()
        setupHeader()
        setupChatPreview()
        setupThemeSection()
        setupWallpaperSection()
        updateSelection()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: animated)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        setupFullWidthSwipeBack()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        layoutHeader()
        layoutThemeDividers()
    }

    private func layoutThemeDividers() {
        let w = themeCard.bounds.width
        let h = themeCard.bounds.height
        let dividerH: CGFloat = 24
        let y = (h - dividerH) / 2
        for (i, divider) in themeDividers.enumerated() {
            let x = w * CGFloat(i + 1) / 3.0
            divider.frame = CGRect(x: x, y: y, width: 0.5, height: dividerH)
        }
    }

    // MARK: - Full-Width Swipe Back

    private var addedSwipeBackGesture = false

    private func setupFullWidthSwipeBack() {
        guard !addedSwipeBackGesture else { return }
        addedSwipeBackGesture = true

        guard let nav = navigationController,
              let edgeGesture = nav.interactivePopGestureRecognizer,
              let targets = edgeGesture.value(forKey: "targets") as? NSArray,
              targets.count > 0 else { return }

        edgeGesture.isEnabled = true

        let fullWidthGesture = UIPanGestureRecognizer()
        fullWidthGesture.setValue(targets, forKey: "targets")
        fullWidthGesture.delegate = self
        nav.view.addGestureRecognizer(fullWidthGesture)
    }

    // MARK: - Header

    private func setupHeader() {
        let back = AppearanceBackButton()
        back.addTarget(self, action: #selector(backTapped), for: .touchUpInside)
        back.layer.zPosition = 55
        view.addSubview(back)
        backButton = back

        titleLabel.text = "Appearance"
        titleLabel.font = .systemFont(ofSize: 17, weight: .semibold)
        titleLabel.textColor = UIColor(RosettaColors.Adaptive.text)
        titleLabel.textAlignment = .center
        titleLabel.layer.zPosition = 55
        view.addSubview(titleLabel)
    }

    private func layoutHeader() {
        let safeTop = view.safeAreaInsets.top
        let centerY = safeTop + headerBarHeight * 0.5

        let sideMargin: CGFloat = 8
        let backSize: CGFloat = 44
        backButton.frame = CGRect(
            x: sideMargin,
            y: centerY - backSize * 0.5,
            width: backSize,
            height: backSize
        )

        let titleWidth: CGFloat = 200
        titleLabel.frame = CGRect(
            x: (view.bounds.width - titleWidth) * 0.5,
            y: centerY - 22,
            width: titleWidth,
            height: 44
        )

        // Update scroll inset
        let headerTotal = safeTop + headerBarHeight + 8
        scrollView.contentInset.top = headerTotal
        scrollView.verticalScrollIndicatorInsets.top = headerTotal
    }

    @objc private func backTapped() {
        navigationController?.popViewController(animated: true)
    }

    // MARK: - Scroll View

    private func setupScrollView() {
        scrollView.showsVerticalScrollIndicator = false
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scrollView)
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: view.topAnchor),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])

        contentStack.axis = .vertical
        contentStack.spacing = 24
        contentStack.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(contentStack)
        NSLayoutConstraint.activate([
            contentStack.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor, constant: 16),
            contentStack.leadingAnchor.constraint(equalTo: scrollView.frameLayoutGuide.leadingAnchor, constant: 16),
            contentStack.trailingAnchor.constraint(equalTo: scrollView.frameLayoutGuide.trailingAnchor, constant: -16),
            contentStack.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor, constant: -100),
        ])
    }

    // MARK: - Chat Preview

    private func setupChatPreview() {
        previewContainer.layer.cornerRadius = 20
        previewContainer.layer.cornerCurve = .continuous
        previewContainer.clipsToBounds = true

        previewWallpaperView.contentMode = .scaleAspectFill
        previewWallpaperView.clipsToBounds = true
        previewWallpaperView.translatesAutoresizingMaskIntoConstraints = false
        previewContainer.addSubview(previewWallpaperView)
        NSLayoutConstraint.activate([
            previewWallpaperView.topAnchor.constraint(equalTo: previewContainer.topAnchor),
            previewWallpaperView.leadingAnchor.constraint(equalTo: previewContainer.leadingAnchor),
            previewWallpaperView.trailingAnchor.constraint(equalTo: previewContainer.trailingAnchor),
            previewWallpaperView.bottomAnchor.constraint(equalTo: previewContainer.bottomAnchor),
        ])

        // Incoming bubble
        let inLabel = UILabel()
        inLabel.text = "Hey! How's it going?"
        inLabel.font = .systemFont(ofSize: 15)
        inLabel.textColor = UIColor(RosettaColors.Adaptive.text)
        inLabel.translatesAutoresizingMaskIntoConstraints = false

        incomingBubble.backgroundColor = UIColor(RosettaColors.Adaptive.messageBubble)
        incomingBubble.layer.cornerRadius = 18
        incomingBubble.layer.cornerCurve = .continuous
        incomingBubble.translatesAutoresizingMaskIntoConstraints = false
        incomingBubble.addSubview(inLabel)
        NSLayoutConstraint.activate([
            inLabel.topAnchor.constraint(equalTo: incomingBubble.topAnchor, constant: 8),
            inLabel.leadingAnchor.constraint(equalTo: incomingBubble.leadingAnchor, constant: 14),
            inLabel.trailingAnchor.constraint(equalTo: incomingBubble.trailingAnchor, constant: -14),
            inLabel.bottomAnchor.constraint(equalTo: incomingBubble.bottomAnchor, constant: -8),
        ])
        previewContainer.addSubview(incomingBubble)

        // Outgoing bubble
        let outLabel = UILabel()
        outLabel.text = "Great, thanks!"
        outLabel.font = .systemFont(ofSize: 15)
        outLabel.textColor = .white // always white on blue bubble
        outLabel.translatesAutoresizingMaskIntoConstraints = false

        outgoingBubble.backgroundColor = UIColor(RosettaColors.primaryBlue)
        outgoingBubble.layer.cornerRadius = 18
        outgoingBubble.layer.cornerCurve = .continuous
        outgoingBubble.translatesAutoresizingMaskIntoConstraints = false
        outgoingBubble.addSubview(outLabel)
        NSLayoutConstraint.activate([
            outLabel.topAnchor.constraint(equalTo: outgoingBubble.topAnchor, constant: 8),
            outLabel.leadingAnchor.constraint(equalTo: outgoingBubble.leadingAnchor, constant: 14),
            outLabel.trailingAnchor.constraint(equalTo: outgoingBubble.trailingAnchor, constant: -14),
            outLabel.bottomAnchor.constraint(equalTo: outgoingBubble.bottomAnchor, constant: -8),
        ])
        previewContainer.addSubview(outgoingBubble)

        // Layout bubbles
        NSLayoutConstraint.activate([
            incomingBubble.leadingAnchor.constraint(equalTo: previewContainer.leadingAnchor, constant: 12),
            incomingBubble.bottomAnchor.constraint(equalTo: outgoingBubble.topAnchor, constant: -6),

            outgoingBubble.trailingAnchor.constraint(equalTo: previewContainer.trailingAnchor, constant: -12),
            outgoingBubble.bottomAnchor.constraint(equalTo: previewContainer.bottomAnchor, constant: -12),
        ])

        previewContainer.translatesAutoresizingMaskIntoConstraints = false
        contentStack.addArrangedSubview(previewContainer)
        previewContainer.heightAnchor.constraint(equalToConstant: 200).isActive = true
    }

    // MARK: - Theme Section

    private func setupThemeSection() {
        themeSectionLabel.text = "COLOR THEME"
        themeSectionLabel.font = .systemFont(ofSize: 13, weight: .medium)
        themeSectionLabel.textColor = UIColor(RosettaColors.Adaptive.textSecondary)

        let sectionStack = UIStackView()
        sectionStack.axis = .vertical
        sectionStack.spacing = 10

        let labelWrapper = UIView()
        themeSectionLabel.translatesAutoresizingMaskIntoConstraints = false
        labelWrapper.addSubview(themeSectionLabel)
        NSLayoutConstraint.activate([
            themeSectionLabel.leadingAnchor.constraint(equalTo: labelWrapper.leadingAnchor, constant: 4),
            themeSectionLabel.topAnchor.constraint(equalTo: labelWrapper.topAnchor),
            themeSectionLabel.bottomAnchor.constraint(equalTo: labelWrapper.bottomAnchor),
        ])
        sectionStack.addArrangedSubview(labelWrapper)

        // Card
        themeCard.backgroundColor = UIColor { $0.userInterfaceStyle == .dark
            ? UIColor(red: 28/255, green: 28/255, blue: 30/255, alpha: 1)
            : UIColor(red: 242/255, green: 242/255, blue: 247/255, alpha: 1)
        }
        themeCard.layer.cornerRadius = 26
        themeCard.layer.cornerCurve = .continuous

        let buttonStack = UIStackView()
        buttonStack.axis = .horizontal
        buttonStack.distribution = .fillEqually
        buttonStack.translatesAutoresizingMaskIntoConstraints = false
        themeCard.addSubview(buttonStack)
        NSLayoutConstraint.activate([
            buttonStack.topAnchor.constraint(equalTo: themeCard.topAnchor),
            buttonStack.leadingAnchor.constraint(equalTo: themeCard.leadingAnchor),
            buttonStack.trailingAnchor.constraint(equalTo: themeCard.trailingAnchor),
            buttonStack.bottomAnchor.constraint(equalTo: themeCard.bottomAnchor),
        ])

        for (index, mode) in ThemeMode.allCases.enumerated() {
            let btn = UIButton(type: .system)
            btn.tag = index
            btn.addTarget(self, action: #selector(themeButtonTapped(_:)), for: .touchUpInside)

            var config = UIButton.Configuration.plain()
            config.image = UIImage(systemName: mode.iconName)?.withConfiguration(
                UIImage.SymbolConfiguration(pointSize: 14)
            )
            config.title = mode.label
            config.imagePadding = 8
            btn.configuration = config
            btn.tintColor = UIColor(RosettaColors.Adaptive.textSecondary)

            themeButtons[mode] = btn
            buttonStack.addArrangedSubview(btn)
        }

        // Dividers — added to themeCard directly (not the stack), positioned in layoutSubviews
        for _ in 0..<2 {
            let divider = UIView()
            divider.backgroundColor = UIColor(RosettaColors.Adaptive.divider)
            themeCard.addSubview(divider)
            themeDividers.append(divider)
        }

        themeCard.translatesAutoresizingMaskIntoConstraints = false
        themeCard.heightAnchor.constraint(equalToConstant: 52).isActive = true
        sectionStack.addArrangedSubview(themeCard)
        contentStack.addArrangedSubview(sectionStack)
    }

    @objc private func themeButtonTapped(_ sender: UIButton) {
        let mode = ThemeMode.allCases[sender.tag]
        themeModeRaw = mode.rawValue
        updateThemeButtons()
        applyThemeMode(mode)
    }

    private func updateThemeButtons() {
        let current = themeMode
        let blue = UIColor(RosettaColors.primaryBlue)
        let secondary = UIColor(RosettaColors.Adaptive.textSecondary)
        let text = UIColor(RosettaColors.Adaptive.text)

        for mode in ThemeMode.allCases {
            guard let btn = themeButtons[mode] else { continue }
            let isActive = mode == current
            btn.tintColor = isActive ? blue : secondary

            var config = btn.configuration ?? .plain()
            var titleAttr = AttributeContainer()
            titleAttr.font = .systemFont(ofSize: 15, weight: isActive ? .semibold : .regular)
            titleAttr.foregroundColor = isActive ? blue : text
            config.attributedTitle = AttributedString(mode.label, attributes: titleAttr)
            btn.configuration = config
        }
    }

    private func applyThemeMode(_ mode: ThemeMode) {
        guard let windowScene = UIApplication.shared.connectedScenes
            .compactMap({ $0 as? UIWindowScene })
            .first(where: { $0.activationState == .foregroundActive })
                ?? UIApplication.shared.connectedScenes
            .compactMap({ $0 as? UIWindowScene }).first
        else { return }

        let style: UIUserInterfaceStyle
        switch mode {
        case .dark: style = .dark
        case .light: style = .light
        case .system: style = .unspecified
        }

        for window in windowScene.windows {
            window.overrideUserInterfaceStyle = style
        }
    }

    // MARK: - Wallpaper Section

    private func setupWallpaperSection() {
        wallpaperSectionLabel.text = "CHAT BACKGROUND"
        wallpaperSectionLabel.font = .systemFont(ofSize: 13, weight: .medium)
        wallpaperSectionLabel.textColor = UIColor(RosettaColors.Adaptive.textSecondary)

        let sectionStack = UIStackView()
        sectionStack.axis = .vertical
        sectionStack.spacing = 10

        let labelWrapper = UIView()
        wallpaperSectionLabel.translatesAutoresizingMaskIntoConstraints = false
        labelWrapper.addSubview(wallpaperSectionLabel)
        NSLayoutConstraint.activate([
            wallpaperSectionLabel.leadingAnchor.constraint(equalTo: labelWrapper.leadingAnchor, constant: 4),
            wallpaperSectionLabel.topAnchor.constraint(equalTo: labelWrapper.topAnchor),
            wallpaperSectionLabel.bottomAnchor.constraint(equalTo: labelWrapper.bottomAnchor),
        ])
        sectionStack.addArrangedSubview(labelWrapper)

        // Grid: 3 columns
        let options = WallpaperOption.allOptions
        let columns = 3
        let rows = Int(ceil(Double(options.count) / Double(columns)))

        let gridStack = UIStackView()
        gridStack.axis = .vertical
        gridStack.spacing = 10

        for row in 0..<rows {
            let rowStack = UIStackView()
            rowStack.axis = .horizontal
            rowStack.spacing = 10
            rowStack.distribution = .fillEqually

            for col in 0..<columns {
                let idx = row * columns + col
                if idx < options.count {
                    let option = options[idx]
                    let cell = WallpaperCellView(option: option)
                    cell.onTap = { [weak self] in
                        self?.selectWallpaper(option.id)
                    }
                    cell.heightAnchor.constraint(equalToConstant: 140).isActive = true
                    rowStack.addArrangedSubview(cell)
                    wallpaperCells[option.id] = cell
                } else {
                    let spacer = UIView()
                    rowStack.addArrangedSubview(spacer)
                }
            }

            gridStack.addArrangedSubview(rowStack)
        }

        sectionStack.addArrangedSubview(gridStack)
        contentStack.addArrangedSubview(sectionStack)
    }

    private func selectWallpaper(_ id: String) {
        selectedWallpaperId = id
        updateSelection()
    }

    // MARK: - Update State

    private func updateSelection() {
        let selected = selectedWallpaperId

        // Update wallpaper cells
        for (id, cell) in wallpaperCells {
            cell.setSelected(id == selected)
        }

        // Update preview
        let option = WallpaperOption.allOptions.first(where: { $0.id == selected })
            ?? WallpaperOption.allOptions[0]
        switch option.style {
        case .none:
            previewWallpaperView.image = nil
            previewContainer.backgroundColor = UIColor(RosettaColors.Adaptive.background)
        case .image(let assetName):
            previewWallpaperView.image = UIImage(named: assetName)
            previewContainer.backgroundColor = .clear
        }

        // Update theme buttons
        updateThemeButtons()
    }

    // MARK: - Trait Changes

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
            updateSelection()
        }
    }
}

// MARK: - UIGestureRecognizerDelegate

extension AppearanceViewController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        guard let pan = gestureRecognizer as? UIPanGestureRecognizer else { return false }
        let velocity = pan.velocity(in: pan.view)
        return velocity.x > 0 && abs(velocity.x) > abs(velocity.y)
    }

    func gestureRecognizer(
        _ gestureRecognizer: UIGestureRecognizer,
        shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer
    ) -> Bool { false }
}

// MARK: - Back Button (glass circle + chevron)

private final class AppearanceBackButton: UIControl {

    private let glassView = TelegramGlassUIView(frame: .zero)
    private let chevronLayer = CAShapeLayer()
    private static let viewBox = CGSize(width: 10.7, height: 19.63)

    override init(frame: CGRect) {
        super.init(frame: frame)
        glassView.isUserInteractionEnabled = false
        addSubview(glassView)

        chevronLayer.fillColor = UIColor { $0.userInterfaceStyle == .dark ? .white : .black }.cgColor
        layer.addSublayer(chevronLayer)
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError() }

    override var intrinsicContentSize: CGSize { CGSize(width: 44, height: 44) }

    override func layoutSubviews() {
        super.layoutSubviews()
        glassView.frame = bounds
        glassView.fixedCornerRadius = bounds.height * 0.5
        glassView.updateGlass()

        guard bounds.width > 0 else { return }
        let iconSize = CGSize(width: 11, height: 20)
        let origin = CGPoint(
            x: (bounds.width - iconSize.width) / 2,
            y: (bounds.height - iconSize.height) / 2
        )
        var parser = SVGPathParser(pathData: TelegramIconPath.backChevron)
        let rawPath = parser.parse()
        let vb = Self.viewBox
        var transform = CGAffineTransform(translationX: origin.x, y: origin.y)
            .scaledBy(x: iconSize.width / vb.width, y: iconSize.height / vb.height)
        chevronLayer.path = rawPath.copy(using: &transform)
        chevronLayer.frame = bounds
    }

    override var isHighlighted: Bool {
        didSet { alpha = isHighlighted ? 0.6 : 1.0 }
    }

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
            chevronLayer.fillColor = UIColor { $0.userInterfaceStyle == .dark ? .white : .black }.cgColor
        }
    }
}

// MARK: - Wallpaper Cell View

private final class WallpaperCellView: UIView {

    var onTap: (() -> Void)?

    private let imageView = UIImageView()
    private let noneLabel = UILabel()
    private let checkmarkView = UIImageView()
    private let borderLayer = CAShapeLayer()
    private let option: WallpaperOption

    init(option: WallpaperOption) {
        self.option = option
        super.init(frame: .zero)
        setupUI()
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError() }

    private func setupUI() {
        layer.cornerRadius = 14
        layer.cornerCurve = .continuous
        clipsToBounds = true

        // Wallpaper image
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(imageView)
        NSLayoutConstraint.activate([
            imageView.topAnchor.constraint(equalTo: topAnchor),
            imageView.leadingAnchor.constraint(equalTo: leadingAnchor),
            imageView.trailingAnchor.constraint(equalTo: trailingAnchor),
            imageView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])

        switch option.style {
        case .none:
            imageView.image = nil
            backgroundColor = UIColor(RosettaColors.Adaptive.background)

            noneLabel.text = "None"
            noneLabel.font = .systemFont(ofSize: 13, weight: .medium)
            noneLabel.textColor = UIColor(RosettaColors.Adaptive.textSecondary)
            noneLabel.textAlignment = .center
            noneLabel.translatesAutoresizingMaskIntoConstraints = false
            addSubview(noneLabel)
            NSLayoutConstraint.activate([
                noneLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
                noneLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
            ])

        case .image(let assetName):
            imageView.image = UIImage(named: assetName)
        }

        // Checkmark
        let config = UIImage.SymbolConfiguration(pointSize: 22)
        checkmarkView.image = UIImage(systemName: "checkmark.circle.fill", withConfiguration: config)
        checkmarkView.tintColor = UIColor(RosettaColors.primaryBlue)
        checkmarkView.isHidden = true
        checkmarkView.translatesAutoresizingMaskIntoConstraints = false

        let checkBg = UIView()
        checkBg.backgroundColor = .white
        checkBg.layer.cornerRadius = 9
        checkBg.translatesAutoresizingMaskIntoConstraints = false

        addSubview(checkBg)
        addSubview(checkmarkView)
        NSLayoutConstraint.activate([
            checkmarkView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
            checkmarkView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
            checkmarkView.widthAnchor.constraint(equalToConstant: 22),
            checkmarkView.heightAnchor.constraint(equalToConstant: 22),

            checkBg.centerXAnchor.constraint(equalTo: checkmarkView.centerXAnchor),
            checkBg.centerYAnchor.constraint(equalTo: checkmarkView.centerYAnchor),
            checkBg.widthAnchor.constraint(equalToConstant: 18),
            checkBg.heightAnchor.constraint(equalToConstant: 18),
        ])
        self.checkmarkBackground = checkBg

        // Border
        borderLayer.fillColor = nil
        borderLayer.lineWidth = 0.5
        borderLayer.strokeColor = UIColor.white.withAlphaComponent(0.1).cgColor
        layer.addSublayer(borderLayer)

        // Tap
        let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        addGestureRecognizer(tap)
    }

    private var checkmarkBackground: UIView!

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

    func setSelected(_ selected: Bool) {
        checkmarkView.isHidden = !selected
        checkmarkBackground.isHidden = !selected

        let blue = UIColor(RosettaColors.primaryBlue)
        borderLayer.strokeColor = selected
            ? blue.cgColor
            : UIColor.white.withAlphaComponent(0.1).cgColor
        borderLayer.lineWidth = selected ? 2 : 0.5
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        let path = UIBezierPath(
            roundedRect: bounds.insetBy(dx: borderLayer.lineWidth / 2, dy: borderLayer.lineWidth / 2),
            cornerRadius: 14
        )
        borderLayer.path = path.cgPath
        borderLayer.frame = bounds
    }

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
            if case .image(let assetName) = option.style {
                imageView.image = UIImage(named: assetName)
            }
        }
    }
}

// MARK: - SwiftUI Bridge (for legacy SettingsView navigation path)

struct AppearanceViewRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> AppearanceViewController {
        AppearanceViewController()
    }
    func updateUIViewController(_ uiViewController: AppearanceViewController, context: Context) {}
}
