import SwiftUI
import UIKit

// MARK: - SettingsViewController

/// Pure UIKit Settings screen — replaces SwiftUI SettingsView.
/// Frame-based layout (Telegram pattern), no Auto Layout.
/// Sub-screens (Appearance, Updates, Safety, Backup) stay SwiftUI via UIHostingController.
final class SettingsViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate {

    // MARK: - Callbacks

    var onLogout: (() -> Void)?
    var onAddAccount: ((AuthScreen) -> Void)?
    /// Reports editing/detail state to parent so tab bar hides when appropriate.
    var onEditingStateChanged: ((Bool) -> Void)?
    var onDetailStateChanged: ((Bool) -> Void)?

    // MARK: - State

    private let viewModel = SettingsViewModel()
    private var avatarImage: UIImage?
    private var isBiometricEnabled = false
    private let acctDeleteWidth: CGFloat = 80
    private weak var revealedAccountRow: UIView? // currently swiped-open row

    // MARK: - Views

    private let scrollView = UIScrollView()
    private let contentView = UIView()
    private let toolbarView = UIView()

    // Profile header
    private let avatarContainer = UIView()
    private var avatarHosting: UIHostingController<AvatarView>?
    private let nameLabel = UILabel()
    private let usernameLabel = UILabel()
    private var publicKeyView: CopyableLabel?

    // Cards
    private var accountCard: UIView?
    private var appearanceCard: UIView!
    private var updatesCard: UIView!
    private var biometricCard: UIView?
    private let biometricSwitch = UISwitch()
    private var safetyCard: UIView!
    private var footerView: UIView!

    // Toolbar buttons (DarkModeButton is SwiftUI — uses circular reveal animation + AppStorage theme)
    private var darkModeHosting: UIHostingController<AnyView>?
    private var editHosting: UIHostingController<AnyView>?

    // MARK: - Layout Constants

    private let hPad: CGFloat = 16
    private let cardCornerRadius: CGFloat = 26
    private let rowHeight: CGFloat = 52
    private let iconSize: CGFloat = 26
    private let iconCornerRadius: CGFloat = 6
    private let cardFill = UIColor { traits in
        traits.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)
    }

    // Account section (Telegram parity)
    private let acctSectionRadius: CGFloat = 26
    private let acctRowH: CGFloat = 56
    private let addAcctRowH: CGFloat = 52
    private let acctAvatarSize: CGFloat = 40

    // MARK: - Lifecycle

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

        setupScrollView()
        setupToolbar()
        setupProfileHeader()
        setupAccountSection()
        setupCards()
        setupFooter()

        refresh()

        NotificationCenter.default.addObserver(
            self, selector: #selector(profileDidUpdate),
            name: .profileDidUpdate, object: nil
        )
    }

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

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        layoutAll()
    }

    @objc private func profileDidUpdate() {
        refresh()
    }

    // MARK: - Refresh

    private func refresh() {
        viewModel.refresh()
        avatarImage = AvatarRepository.shared.loadAvatar(publicKey: viewModel.publicKey)
        refreshBiometricState()
        rebuildAccountSection()
        updateProfileHeader()
    }

    // MARK: - Setup Scroll View

    private func setupScrollView() {
        scrollView.delegate = self
        scrollView.showsVerticalScrollIndicator = false
        scrollView.alwaysBounceVertical = true
        scrollView.backgroundColor = .clear
        view.addSubview(scrollView)

        contentView.backgroundColor = .clear
        scrollView.addSubview(contentView)
    }

    // MARK: - Setup Toolbar

    private func setupToolbar() {
        toolbarView.backgroundColor = .clear
        view.addSubview(toolbarView)

        // Dark mode button — SwiftUI DarkModeButton (circular reveal animation + theme system)
        let darkModeView = AnyView(
            DarkModeButton()
                .glassCircle()
                .frame(maxWidth: .infinity, alignment: .leading)
        )
        let darkHosting = UIHostingController(rootView: darkModeView)
        darkHosting.view.backgroundColor = .clear
        addChild(darkHosting)
        toolbarView.addSubview(darkHosting.view)
        darkHosting.didMove(toParent: self)
        darkModeHosting = darkHosting

        // Edit button — SwiftUI for glass consistency
        let editView = AnyView(
            SettingsEditButton { [weak self] in
                self?.editTapped()
            }
            .frame(maxWidth: .infinity, alignment: .trailing)
        )
        let editHost = UIHostingController(rootView: editView)
        editHost.view.backgroundColor = UIColor.clear
        addChild(editHost)
        toolbarView.addSubview(editHost.view)
        editHost.didMove(toParent: self)
        editHosting = editHost
    }

    // MARK: - Setup Profile Header

    private func setupProfileHeader() {
        contentView.addSubview(avatarContainer)

        nameLabel.font = .systemFont(ofSize: 22, weight: .bold)
        nameLabel.textColor = UIColor(RosettaColors.Adaptive.text)
        nameLabel.textAlignment = .center
        contentView.addSubview(nameLabel)

        usernameLabel.font = .systemFont(ofSize: 15, weight: .regular)
        usernameLabel.textColor = UIColor(RosettaColors.secondaryText)
        usernameLabel.textAlignment = .center
        contentView.addSubview(usernameLabel)

        let pkView = CopyableLabel()
        pkView.font = .monospacedSystemFont(ofSize: 12, weight: .regular)
        pkView.textColor = UIColor(RosettaColors.tertiaryText)
        pkView.textAlignment = .center
        contentView.addSubview(pkView)
        publicKeyView = pkView
    }

    // MARK: - Setup Cards

    private func setupCards() {
        appearanceCard = makeSettingsCard(
            icon: "paintbrush.fill", title: "Appearance", iconColor: .systemBlue,
            subtitle: "Customize theme, wallpaper and chat appearance.",
            action: #selector(appearanceTapped)
        )
        contentView.addSubview(appearanceCard)

        updatesCard = makeSettingsCard(
            icon: "arrow.triangle.2.circlepath", title: "Updates", iconColor: .systemGreen,
            subtitle: "You can check for new versions of the app here. Updates may include security improvements and new features.",
            action: #selector(updatesTapped)
        )
        contentView.addSubview(updatesCard)

        if BiometricAuthManager.shared.isBiometricAvailable {
            let card = makeBiometricCard()
            contentView.addSubview(card)
            biometricCard = card
        }

        safetyCard = makeSettingsCard(
            icon: "shield.lefthalf.filled", title: "Safety", iconColor: .systemPurple,
            subtitle: "You can learn more about your safety on the safety page, please make sure you are viewing the screen alone before proceeding to the safety page.",
            action: #selector(safetyTapped)
        )
        contentView.addSubview(safetyCard)
    }

    // MARK: - Setup Footer

    private func setupFooter() {
        let footer = UIView()
        let label = UILabel()
        label.text = "rosetta – powering freedom"
        label.font = .systemFont(ofSize: 12)
        label.textColor = UIColor(RosettaColors.tertiaryText)
        label.textAlignment = .center
        footer.addSubview(label)
        label.tag = 100
        contentView.addSubview(footer)
        footerView = footer
    }

    // MARK: - Layout

    private func layoutAll() {
        let w = view.bounds.width
        let safeTop = view.safeAreaInsets.top
        let safeBottom = view.safeAreaInsets.bottom

        // Scroll view: full screen
        scrollView.frame = view.bounds

        // Toolbar: pinned at top in safe area
        let toolbarH: CGFloat = 44
        toolbarView.frame = CGRect(x: 0, y: safeTop, width: w, height: toolbarH)

        let toolbarBtnW: CGFloat = 100
        darkModeHosting?.view.frame = CGRect(x: hPad, y: 0, width: toolbarBtnW, height: 44)
        editHosting?.view.frame = CGRect(x: w - hPad - toolbarBtnW, y: 0, width: toolbarBtnW, height: 44)

        // Content layout
        var y: CGFloat = safeTop + toolbarH + 15

        // Avatar (100×100, centered)
        let avatarSize: CGFloat = 100
        let avatarX = floor((w - avatarSize) / 2)
        avatarContainer.frame = CGRect(x: avatarX, y: y, width: avatarSize, height: avatarSize)
        layoutAvatarHosting()
        y += avatarSize + 12

        // Name
        nameLabel.sizeToFit()
        nameLabel.frame = CGRect(x: hPad, y: y, width: w - hPad * 2, height: 28)
        y += 28

        // Username
        if !usernameLabel.isHidden {
            usernameLabel.frame = CGRect(x: hPad, y: y, width: w - hPad * 2, height: 20)
            y += 24
        }

        // Public key
        if let pkView = publicKeyView {
            pkView.frame = CGRect(x: hPad, y: y, width: w - hPad * 2, height: 16)
            y += 28
        }

        // Account section
        let cardW = w - hPad * 2
        if let acctSection = accountCard {
            y += 20
            layoutAccountSection(acctSection, y: &y, width: cardW)
        }

        // Cards
        y += 16
        layoutCard(appearanceCard, x: hPad, y: &y, width: cardW)
        y += 16
        layoutCard(updatesCard, x: hPad, y: &y, width: cardW)

        if let bioCard = biometricCard {
            y += 16
            layoutCard(bioCard, x: hPad, y: &y, width: cardW)
        }

        y += 16
        layoutCard(safetyCard, x: hPad, y: &y, width: cardW)

        // Footer
        y += 32
        footerView.frame = CGRect(x: hPad, y: y, width: cardW, height: 20)
        if let label = footerView.viewWithTag(100) as? UILabel {
            label.frame = CGRect(x: 0, y: 0, width: cardW, height: 20)
        }
        y += 20

        // Content size
        let contentH = y + safeBottom + 100
        contentView.frame = CGRect(x: 0, y: 0, width: w, height: contentH)
        scrollView.contentSize = CGSize(width: w, height: contentH)
    }

    private func layoutCard(_ card: UIView, x: CGFloat, y: inout CGFloat, width: CGFloat) {
        // Card has: row (52pt) + subtitle label
        let rowView = card.viewWithTag(200)
        let subtitleLabel = card.viewWithTag(201) as? UILabel
        let bgView = card.viewWithTag(199)

        let subtitleH: CGFloat
        if let sub = subtitleLabel, let text = sub.text, !text.isEmpty {
            let maxW = width - 32
            let size = sub.sizeThatFits(CGSize(width: maxW, height: .greatestFiniteMagnitude))
            subtitleH = size.height + 16
            sub.frame = CGRect(x: 16, y: rowHeight + 8, width: maxW, height: size.height)
        } else {
            subtitleH = 0
        }

        let totalH = rowHeight + subtitleH
        card.frame = CGRect(x: x, y: y, width: width, height: totalH)
        bgView?.frame = CGRect(x: 0, y: 0, width: width, height: rowHeight)
        rowView?.frame = CGRect(x: 0, y: 0, width: width, height: rowHeight)

        y += totalH
    }

    // MARK: - Avatar

    private func layoutAvatarHosting() {
        let size = avatarContainer.bounds.size
        guard size.width > 0 else { return }

        if let hosting = avatarHosting {
            hosting.view.frame = CGRect(origin: .zero, size: size)
        }
    }

    private func updateAvatarHosting() {
        let avatarView = AvatarView(
            initials: viewModel.initials,
            colorIndex: viewModel.avatarColorIndex,
            size: 100,
            isSavedMessages: false,
            image: avatarImage
        )

        if let hosting = avatarHosting {
            hosting.rootView = avatarView
        } else {
            let hosting = UIHostingController(rootView: avatarView)
            hosting.view.backgroundColor = .clear
            addChild(hosting)
            avatarContainer.addSubview(hosting.view)
            hosting.didMove(toParent: self)
            avatarHosting = hosting
        }
        layoutAvatarHosting()
    }

    // MARK: - Update Profile Header

    private func updateProfileHeader() {
        nameLabel.text = viewModel.headerName
        usernameLabel.text = viewModel.username.isEmpty ? nil : "@\(viewModel.username)"
        usernameLabel.isHidden = viewModel.username.isEmpty

        let pk = viewModel.publicKey
        let displayPK = pk.count > 16
            ? String(pk.prefix(8)) + "..." + String(pk.suffix(6))
            : pk
        publicKeyView?.text = displayPK
        publicKeyView?.textToCopy = pk

        updateAvatarHosting()
        biometricSwitch.isOn = isBiometricEnabled
        view.setNeedsLayout()
    }

    // MARK: - Account Section (Telegram PeerInfoSettingsItems parity)

    private func setupAccountSection() {
        rebuildAccountSection()
    }

    /// Other accounts (excluding the current one). Rebuilt on refresh.
    private var otherAccounts: [Account] = []

    private func rebuildAccountSection() {
        accountCard?.removeFromSuperview()
        accountCard = nil
        revealedAccountRow = nil

        let currentPK = AccountManager.shared.activeAccountPublicKey
        otherAccounts = AccountManager.shared.allAccounts.filter { $0.publicKey != currentPK }

        // Always show the section (even with 0 other accounts — "Add Account" is always visible)
        let container = UIView()
        container.backgroundColor = .clear

        let bg = UIView()
        bg.backgroundColor = cardFill
        bg.layer.cornerRadius = acctSectionRadius
        bg.layer.cornerCurve = .continuous
        bg.clipsToBounds = true
        bg.tag = 300
        container.addSubview(bg)

        // Other account rows (Telegram: only shows non-active accounts)
        for (i, account) in otherAccounts.enumerated() {
            let row = makeAccountRow(account, isCurrent: false, index: i)
            bg.addSubview(row)

            let sep = UIView()
            sep.backgroundColor = UIColor.separator.withAlphaComponent(0.4)
            sep.tag = 350 + i
            bg.addSubview(sep)
        }

        let addRow = makeAddAccountRow()
        addRow.tag = 399
        bg.addSubview(addRow)

        contentView.addSubview(container)
        accountCard = container
    }

    private func makeAccountRow(_ account: Account, isCurrent: Bool, index: Int) -> UIView {
        let row = UIView()
        row.tag = 600 + index
        row.clipsToBounds = true

        // Delete button (behind content, right-aligned, Telegram: destructive red)
        if !isCurrent {
            let deleteBtn = UIButton(type: .system)
            deleteBtn.setTitle("Log Out", for: .normal)
            deleteBtn.setTitleColor(.white, for: .normal)
            deleteBtn.titleLabel?.font = .systemFont(ofSize: 17, weight: .regular)
            deleteBtn.backgroundColor = .systemRed
            deleteBtn.tag = 502
            deleteBtn.isHidden = true
            deleteBtn.addTarget(self, action: #selector(deleteAccountTapped(_:)), for: .touchUpInside)
            row.addSubview(deleteBtn)
        }

        // Sliding content container (covers delete button)
        let content = UIView()
        content.backgroundColor = cardFill
        content.tag = 501
        row.addSubview(content)

        // Highlight background
        let highlight = UIView()
        highlight.backgroundColor = UIColor.white.withAlphaComponent(0.08)
        highlight.isHidden = true
        highlight.isUserInteractionEnabled = false
        highlight.tag = 500
        content.addSubview(highlight)

        // Avatar (Telegram: 40pt at x=15, Mantine light variant)
        let name: String = {
            if let dn = account.displayName, !dn.isEmpty { return dn }
            return String(account.publicKey.prefix(7))
        }()
        let initials = RosettaColors.initials(name: name, publicKey: account.publicKey)
        let colorIdx = RosettaColors.avatarColorIndex(for: name, publicKey: account.publicKey)
        let photo = AvatarRepository.shared.loadAvatar(publicKey: account.publicKey)
        let avatar = makeAccountAvatar(initials: initials, colorIndex: colorIdx, size: acctAvatarSize, photo: photo)
        avatar.isUserInteractionEnabled = false
        avatar.tag = 313
        content.addSubview(avatar)

        // Name (Telegram: Font.regular(17), itemPrimaryTextColor)
        let nameLabel = UILabel()
        nameLabel.text = name
        nameLabel.font = .systemFont(ofSize: 17, weight: .regular)
        nameLabel.textColor = UIColor(RosettaColors.Adaptive.text)
        nameLabel.lineBreakMode = .byTruncatingTail
        nameLabel.isUserInteractionEnabled = false
        nameLabel.tag = 311
        content.addSubview(nameLabel)

        // Unread badge (Telegram: badgeDiameter 20, badgeFont 15, accent bg, white text)
        let unread = accountUnreadCount(for: account.publicKey)
        if unread > 0 {
            let badge = makeUnreadBadge(count: unread)
            badge.isUserInteractionEnabled = false
            badge.tag = 312
            content.addSubview(badge)
        }

        // Tap gesture (switch account / close revealed)
        let tap = UITapGestureRecognizer(target: self, action: #selector(accountRowTapGesture(_:)))
        content.addGestureRecognizer(tap)

        // Pan gesture for swipe-to-delete (non-current accounts only)
        if !isCurrent {
            let pan = UIPanGestureRecognizer(target: self, action: #selector(handleAccountSwipe(_:)))
            pan.delegate = self
            row.addGestureRecognizer(pan)
        }

        return row
    }

    private func makeAddAccountRow() -> UIControl {
        let row = UIControl()

        // Highlight
        let highlight = UIView()
        highlight.backgroundColor = UIColor.white.withAlphaComponent(0.08)
        highlight.isHidden = true
        highlight.isUserInteractionEnabled = false
        highlight.tag = 500
        row.addSubview(highlight)

        // "+" icon (Telegram: plusIconImage at sideInset=16, 29x29, accentColor)
        let config = UIImage.SymbolConfiguration(pointSize: 17, weight: .medium)
        let plusImg = UIImageView(image: UIImage(systemName: "plus", withConfiguration: config))
        plusImg.tintColor = UIColor(RosettaColors.primaryBlue)
        plusImg.contentMode = .center
        plusImg.isUserInteractionEnabled = false
        plusImg.tag = 320
        row.addSubview(plusImg)

        // Label (Telegram: Font.regular(17), accentColor)
        let label = UILabel()
        label.text = "Add Account"
        label.font = .systemFont(ofSize: 17, weight: .regular)
        label.textColor = UIColor(RosettaColors.primaryBlue)
        label.isUserInteractionEnabled = false
        label.tag = 321
        row.addSubview(label)

        row.addTarget(self, action: #selector(addAccountTapped), for: .touchUpInside)
        row.addTarget(self, action: #selector(acctTouchDown(_:)), for: [.touchDown, .touchDragEnter])
        row.addTarget(self, action: #selector(acctTouchUp(_:)), for: [.touchUpInside, .touchUpOutside, .touchCancel, .touchDragExit])

        return row
    }

    // MARK: Account Section — Avatar (UIKit, Mantine light variant)

    private func makeAccountAvatar(initials: String, colorIndex: Int, size: CGFloat, photo: UIImage?) -> UIView {
        let container = UIView(frame: CGRect(x: 0, y: 0, width: size, height: size))
        container.layer.cornerRadius = size / 2
        container.clipsToBounds = true

        if let photo {
            let iv = UIImageView(image: photo)
            iv.contentMode = .scaleAspectFill
            iv.frame = container.bounds
            container.addSubview(iv)
        } else {
            let tintColor = RosettaColors.avatarColor(for: colorIndex)
            let textColor = RosettaColors.avatarTextColor(for: colorIndex)
            let isDark = traitCollection.userInterfaceStyle == .dark

            container.backgroundColor = isDark
                ? UIColor(red: 26/255, green: 27/255, blue: 30/255, alpha: 1) // #1A1B1E
                : .white

            let overlay = UIView(frame: container.bounds)
            overlay.backgroundColor = tintColor.withAlphaComponent(isDark ? 0.15 : 0.10)
            container.addSubview(overlay)

            let label = UILabel(frame: container.bounds)
            label.text = initials
            let baseFont = UIFont.systemFont(ofSize: size * 0.38, weight: .bold)
            label.font = baseFont.fontDescriptor.withDesign(.rounded)
                .map { UIFont(descriptor: $0, size: size * 0.38) } ?? baseFont
            label.textColor = isDark ? textColor : tintColor
            label.textAlignment = .center
            container.addSubview(label)
        }
        return container
    }

    // MARK: Account Section — Unread Badge (Telegram: 20pt diameter, accent bg, white 15pt)

    private func makeUnreadBadge(count: Int) -> UIView {
        let text = formattedUnread(count)
        let label = UILabel()
        label.text = text
        label.font = .systemFont(ofSize: 15, weight: .regular)
        label.textColor = .white
        label.textAlignment = .center

        let textSize = label.sizeThatFits(CGSize(width: 200, height: 20))
        let badgeDiameter: CGFloat = 20
        let badgeW = max(badgeDiameter, textSize.width + 12)

        let badge = UIView(frame: CGRect(x: 0, y: 0, width: badgeW, height: badgeDiameter))
        badge.backgroundColor = UIColor(RosettaColors.primaryBlue)
        badge.layer.cornerRadius = badgeDiameter / 2

        label.frame = badge.bounds
        badge.addSubview(label)
        return badge
    }

    // MARK: Account Section — Layout

    private func layoutAccountSection(_ section: UIView, y: inout CGFloat, width: CGFloat) {
        guard let bg = section.viewWithTag(300) else { return }

        let accounts = otherAccounts
        let totalH = CGFloat(accounts.count) * acctRowH + addAcctRowH
        section.frame = CGRect(x: hPad, y: y, width: width, height: totalH)
        bg.frame = CGRect(x: 0, y: 0, width: width, height: totalH)

        let pixel = 1.0 / UIScreen.main.scale
        var rowY: CGFloat = 0

        for i in 0..<accounts.count {
            if let row = bg.viewWithTag(600 + i) {
                row.frame = CGRect(x: 0, y: rowY, width: width, height: acctRowH)

                // Delete button (right edge, behind content)
                if let del = row.viewWithTag(502) as? UIButton {
                    del.frame = CGRect(x: width - acctDeleteWidth, y: 0, width: acctDeleteWidth, height: acctRowH)
                }

                // Sliding content — preserve current x offset (swipe state)
                if let content = row.viewWithTag(501) {
                    let currentX = content.frame.origin.x
                    content.frame = CGRect(x: currentX, y: 0, width: width, height: acctRowH)

                    // Highlight fills content
                    if let hl = content.viewWithTag(500) {
                        hl.frame = content.bounds
                    }

                    // Avatar (Telegram: x=15, centered vertically)
                    if let avatar = content.viewWithTag(313) {
                        avatar.frame = CGRect(
                            x: 15,
                            y: floor((acctRowH - acctAvatarSize) / 2),
                            width: acctAvatarSize,
                            height: acctAvatarSize
                        )
                    }

                    // Badge (right-aligned, Telegram: rightLabelInset 16)
                    var badgeW: CGFloat = 0
                    if let badge = content.viewWithTag(312) {
                        badgeW = badge.bounds.width
                        badge.frame = CGRect(
                            x: width - 16 - badgeW,
                            y: floor((acctRowH - 20) / 2),
                            width: badgeW,
                            height: 20
                        )
                        badgeW += 12
                    }

                    // Name (Telegram: after avatar, single line, truncate before badge)
                    if let name = content.viewWithTag(311) as? UILabel {
                        let nameX: CGFloat = 15 + acctAvatarSize + 12
                        let nameW = width - nameX - 16 - badgeW
                        name.frame = CGRect(
                            x: nameX,
                            y: 0,
                            width: max(0, nameW),
                            height: acctRowH
                        )
                    }
                }
            }

            // Separator (Telegram: left 65, right 16, 1px)
            if let sep = bg.viewWithTag(350 + i) {
                let isLast = i == accounts.count - 1
                // Show separator between all rows (last separator = before Add Account)
                sep.frame = CGRect(
                    x: isLast ? 16 : 65,
                    y: rowY + acctRowH - pixel,
                    width: width - (isLast ? 32 : 81),
                    height: pixel
                )
            }

            rowY += acctRowH
        }

        // "Add Account" row
        if let addRow = bg.viewWithTag(399) {
            addRow.frame = CGRect(x: 0, y: rowY, width: width, height: addAcctRowH)

            if let hl = addRow.viewWithTag(500) {
                hl.frame = addRow.bounds
            }

            // "+" icon (Telegram: x=16, 29x29, centered vertically)
            if let plus = addRow.viewWithTag(320) {
                plus.frame = CGRect(x: 16, y: floor((addAcctRowH - 29) / 2), width: 29, height: 29)
            }

            // Label (Telegram: x = 16 + 29 + 16 = 61)
            if let label = addRow.viewWithTag(321) {
                label.frame = CGRect(x: 61, y: 0, width: width - 61 - 16, height: addAcctRowH)
            }
        }

        y += totalH
    }

    // MARK: Account Section — Actions

    @objc private func accountRowTapGesture(_ sender: UITapGestureRecognizer) {
        // If any row is revealed, close it on tap
        if let revealed = revealedAccountRow, let content = revealed.viewWithTag(501) {
            springSlide(content, to: 0) { revealed.viewWithTag(502)?.isHidden = true }
            revealedAccountRow = nil
            return
        }

        // Find the row tag from the content view's superview
        guard let content = sender.view, let row = content.superview else { return }
        let index = row.tag - 600
        guard index >= 0, index < otherAccounts.count else { return }
        let account = otherAccounts[index]

        // Highlight flash
        let hl = content.viewWithTag(500)
        hl?.isHidden = false
        UIView.animate(withDuration: 0.2) { hl?.isHidden = true }

        // Switch to this account
        onLogout?()
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.04) {
            AccountManager.shared.setActiveAccount(publicKey: account.publicKey)
            SessionManager.shared.endSession()
        }
    }

    @objc private func handleAccountSwipe(_ pan: UIPanGestureRecognizer) {
        guard let row = pan.view, let content = row.viewWithTag(501) else { return }
        let tx = pan.translation(in: row).x

        switch pan.state {
        case .began:
            // Close any other revealed row
            if let other = revealedAccountRow, other !== row, let otherContent = other.viewWithTag(501) {
                springSlide(otherContent, to: 0) { other.viewWithTag(502)?.isHidden = true }
                revealedAccountRow = nil
            }

        case .changed:
            // Cancel any in-flight spring animation for immediate gesture tracking
            content.layer.removeAnimation(forKey: "springSlide")

            // Show delete button as soon as swiping starts
            if tx < -2, let del = row.viewWithTag(502) { del.isHidden = false }

            let isRevealed = content.frame.origin.x < -1
            if isRevealed {
                let newX = -acctDeleteWidth + tx
                content.frame.origin.x = max(min(newX, 0), -acctDeleteWidth - 20)
            } else if tx < 0 {
                content.frame.origin.x = max(tx, -acctDeleteWidth - 20)
            }

        case .ended, .cancelled:
            let velocity = pan.velocity(in: row).x
            // Telegram: velocity >= 100 → direction overrides, else 50% threshold
            let shouldReveal: Bool
            if abs(velocity) >= 100 {
                shouldReveal = velocity < 0
            } else {
                shouldReveal = content.frame.origin.x < -acctDeleteWidth / 2
            }

            // Telegram: CASpringAnimation (mass=3, stiffness=1000, damping=500)
            let targetX = shouldReveal ? -acctDeleteWidth : CGFloat(0)
            springSlide(content, to: targetX) {
                if !shouldReveal { row.viewWithTag(502)?.isHidden = true }
            }
            revealedAccountRow = shouldReveal ? row : nil

        default:
            break
        }
    }

    /// Telegram-parity spring: CASpringAnimation (mass=3, stiffness=1000, damping=500)
    /// Applied directly to CALayer like Telegram's ContainedViewLayoutTransition.
    private func springSlide(
        _ view: UIView,
        to targetX: CGFloat,
        completion: (() -> Void)? = nil
    ) {
        let fromX = view.layer.position.x
        let toX = targetX + view.bounds.width / 2 // position = center

        // Set final value immediately (CA pattern — frame + layer in sync)
        view.frame.origin.x = targetX
        view.layer.position.x = toX

        let spring = CASpringAnimation(keyPath: "position.x")
        spring.fromValue = fromX
        spring.toValue = toX
        spring.mass = 3.0
        spring.stiffness = 1000.0
        spring.damping = 500.0
        spring.initialVelocity = 0
        spring.duration = 0.3
        // Speed adjustment: Telegram scales speed = settlingDuration / requestedDuration
        spring.speed = Float(spring.settlingDuration / 0.3)
        spring.timingFunction = CAMediaTimingFunction(name: .linear)
        spring.fillMode = .forwards
        spring.isRemovedOnCompletion = true

        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        view.layer.add(spring, forKey: "springSlide")
        CATransaction.commit()
    }

    @objc private func deleteAccountTapped(_ sender: UIButton) {
        guard let row = sender.superview else { return }
        let index = row.tag - 600
        guard index >= 0, index < otherAccounts.count else { return }
        let account = otherAccounts[index]

        // Close the revealed row first
        if let content = row.viewWithTag(501) {
            springSlide(content, to: 0) { row.viewWithTag(502)?.isHidden = true }
        }
        revealedAccountRow = nil

        // Confirmation dialog (matches legacy SettingsView)
        let alert = UIAlertController(
            title: nil,
            message: "Are you sure you want to log out of this account?",
            preferredStyle: .actionSheet
        )
        alert.addAction(UIAlertAction(title: "Log Out", style: .destructive) { [weak self] _ in
            self?.performAccountDeletion(account)
        })
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        present(alert, animated: true)
    }

    private func performAccountDeletion(_ account: Account) {
        BiometricAuthManager.shared.clearAll(forAccount: account.publicKey)
        AvatarRepository.shared.removeAvatar(publicKey: account.publicKey)
        let defaults = UserDefaults.standard
        defaults.removeObject(forKey: "rosetta_recent_searches_\(account.publicKey)")
        defaults.removeObject(forKey: "rosetta_last_sync_\(account.publicKey)")
        defaults.removeObject(forKey: "backgroundBlurColor_\(account.publicKey)")
        AccountManager.shared.removeAccount(publicKey: account.publicKey)
        rebuildAccountSection()
        view.setNeedsLayout()
    }

    @objc private func addAccountTapped() {
        let alert = UIAlertController(title: "Add Account", message: nil, preferredStyle: .actionSheet)
        alert.addAction(UIAlertAction(title: "Create New Account", style: .default) { [weak self] _ in
            self?.onAddAccount?(.seedPhrase)
        })
        alert.addAction(UIAlertAction(title: "Import Existing Account", style: .default) { [weak self] _ in
            self?.onAddAccount?(.importSeed)
        })
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        present(alert, animated: true)
    }

    @objc private func acctTouchDown(_ sender: UIControl) {
        sender.viewWithTag(500)?.isHidden = false
    }

    @objc private func acctTouchUp(_ sender: UIControl) {
        UIView.animate(withDuration: 0.2) {
            sender.viewWithTag(500)?.isHidden = true
        }
    }

    // MARK: Account Section — Helpers

    private func accountUnreadCount(for publicKey: String) -> Int {
        guard publicKey == SessionManager.shared.currentPublicKey else { return 0 }
        return DialogRepository.shared.dialogs.values.reduce(0) { $0 + $1.unreadCount }
    }

    private func formattedUnread(_ count: Int) -> String {
        if count >= 1_000_000 {
            let remainder = (count % 1_000_000) / 100_000
            return remainder != 0 ? "\(count / 1_000_000),\(remainder)M" : "\(count / 1_000_000)M"
        } else if count >= 1000 {
            let remainder = (count % 1000) / 100
            return remainder != 0 ? "\(count / 1000),\(remainder)K" : "\(count / 1000)K"
        }
        return "\(count)"
    }

    // MARK: Account Section — Gesture Delegate

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        guard let pan = gestureRecognizer as? UIPanGestureRecognizer else { return true }
        let velocity = pan.velocity(in: pan.view)
        // Only begin if horizontal movement dominates (avoid blocking scroll)
        return abs(velocity.x) > abs(velocity.y)
    }

    // MARK: - Card Factory

    private func makeSettingsCard(
        icon: String, title: String, iconColor: UIColor,
        subtitle: String, action: Selector
    ) -> UIView {
        let container = UIView()

        // Background
        let bg = UIView()
        bg.backgroundColor = cardFill
        bg.layer.cornerRadius = cardCornerRadius
        bg.layer.cornerCurve = .continuous
        bg.tag = 199
        container.addSubview(bg)

        // Row (tappable)
        let row = UIControl()
        row.tag = 200
        row.addTarget(self, action: action, for: .touchUpInside)
        container.addSubview(row)

        // Icon
        let iconBg = UIView()
        iconBg.backgroundColor = iconColor
        iconBg.layer.cornerRadius = iconCornerRadius
        iconBg.frame = CGRect(x: 16, y: (rowHeight - iconSize) / 2, width: iconSize, height: iconSize)
        let iconImg = UIImageView(image: UIImage(
            systemName: icon,
            withConfiguration: UIImage.SymbolConfiguration(pointSize: 14, weight: .medium)
        ))
        iconImg.tintColor = .white
        iconImg.contentMode = .center
        iconImg.frame = iconBg.bounds
        iconBg.addSubview(iconImg)
        row.addSubview(iconBg)

        // Title
        let titleLabel = UILabel()
        titleLabel.text = title
        titleLabel.font = .systemFont(ofSize: 17, weight: .medium)
        titleLabel.textColor = UIColor(RosettaColors.Adaptive.text)
        titleLabel.frame = CGRect(x: 16 + iconSize + 16, y: 0, width: 200, height: rowHeight)
        row.addSubview(titleLabel)

        // Chevron
        let chevron = UIImageView(image: UIImage(
            systemName: "chevron.right",
            withConfiguration: UIImage.SymbolConfiguration(pointSize: 14, weight: .semibold)
        ))
        chevron.tintColor = .tertiaryLabel
        chevron.contentMode = .center
        chevron.frame = CGRect(x: 0, y: 0, width: 20, height: rowHeight)
        chevron.autoresizingMask = [.flexibleLeftMargin]
        row.addSubview(chevron)
        chevron.tag = 202

        // Subtitle
        let sub = UILabel()
        sub.text = subtitle
        sub.font = .systemFont(ofSize: 13)
        sub.textColor = .secondaryLabel
        sub.numberOfLines = 0
        sub.tag = 201
        container.addSubview(sub)

        return container
    }

    private func makeBiometricCard() -> UIView {
        let biometric = BiometricAuthManager.shared
        let container = UIView()

        // Background
        let bg = UIView()
        bg.backgroundColor = cardFill
        bg.layer.cornerRadius = cardCornerRadius
        bg.layer.cornerCurve = .continuous
        bg.tag = 199
        container.addSubview(bg)

        // Row
        let row = UIView()
        row.tag = 200
        container.addSubview(row)

        // Icon
        let iconBg = UIView()
        iconBg.backgroundColor = .systemBlue
        iconBg.layer.cornerRadius = iconCornerRadius
        iconBg.frame = CGRect(x: 16, y: (rowHeight - iconSize) / 2, width: iconSize, height: iconSize)
        let iconImg = UIImageView(image: UIImage(
            systemName: biometric.biometricIconName,
            withConfiguration: UIImage.SymbolConfiguration(pointSize: 14, weight: .medium)
        ))
        iconImg.tintColor = .white
        iconImg.contentMode = .center
        iconImg.frame = iconBg.bounds
        iconBg.addSubview(iconImg)
        row.addSubview(iconBg)

        // Title
        let titleLabel = UILabel()
        titleLabel.text = biometric.biometricName
        titleLabel.font = .systemFont(ofSize: 17, weight: .medium)
        titleLabel.textColor = UIColor(RosettaColors.Adaptive.text)
        titleLabel.frame = CGRect(x: 16 + iconSize + 16, y: 0, width: 200, height: rowHeight)
        row.addSubview(titleLabel)

        // Switch
        biometricSwitch.isOn = isBiometricEnabled
        biometricSwitch.onTintColor = UIColor(RosettaColors.primaryBlue)
        biometricSwitch.addTarget(self, action: #selector(biometricToggled), for: .valueChanged)
        row.addSubview(biometricSwitch)

        // Subtitle
        let sub = UILabel()
        sub.text = "Use \(biometric.biometricName) to unlock Rosetta instead of entering your password."
        sub.font = .systemFont(ofSize: 13)
        sub.textColor = .secondaryLabel
        sub.numberOfLines = 0
        sub.tag = 201
        container.addSubview(sub)

        return container
    }

    // MARK: - Layout Card Fixups

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        // Position chevrons at right edge
        for card in [appearanceCard, updatesCard, safetyCard].compactMap({ $0 }) {
            if let row = card.viewWithTag(200), let chevron = row.viewWithTag(202) as? UIImageView {
                chevron.frame = CGRect(x: row.bounds.width - 36, y: 0, width: 20, height: rowHeight)
            }
        }
        // Position biometric switch
        if let bioCard = biometricCard, let row = bioCard.viewWithTag(200) {
            let switchW: CGFloat = 51
            biometricSwitch.frame = CGRect(
                x: row.bounds.width - switchW - 16,
                y: (rowHeight - 31) / 2,
                width: switchW, height: 31
            )
        }
    }

    // MARK: - Actions

    private func editTapped() {
        let editView = SettingsProfileEditScreen(
            onAddAccount: onAddAccount,
            initialDisplayName: viewModel.displayName,
            initialUsername: viewModel.username,
            publicKey: viewModel.publicKey,
            onExit: { [weak self] in
                guard let self else { return }
                self.onEditingStateChanged?(false)
                self.refresh()
            }
        )
        let hosting = UIHostingController(rootView: editView)
        hosting.view.backgroundColor = UIColor(RosettaColors.Adaptive.background)
        onEditingStateChanged?(true)
        navigationController?.pushViewController(hosting, animated: true)
    }

    @objc private func appearanceTapped() {
        let vc = AppearanceViewController()
        onDetailStateChanged?(true)
        navigationController?.pushViewController(vc, animated: true)
    }

    @objc private func updatesTapped() {
        let hosting = UIHostingController(rootView: UpdatesView())
        hosting.view.backgroundColor = UIColor(RosettaColors.Adaptive.background)
        onDetailStateChanged?(true)
        navigationController?.pushViewController(hosting, animated: true)
    }

    @objc private func safetyTapped() {
        let hosting = UIHostingController(rootView: SafetyView(onLogout: onLogout))
        hosting.view.backgroundColor = UIColor(RosettaColors.Adaptive.background)
        onDetailStateChanged?(true)
        navigationController?.pushViewController(hosting, animated: true)
    }

    @objc private func biometricToggled() {
        let newValue = biometricSwitch.isOn
        if newValue {
            showBiometricPasswordPrompt()
        } else {
            disableBiometric()
        }
    }

    // MARK: - Biometric

    private func refreshBiometricState() {
        let pk = viewModel.publicKey
        guard !pk.isEmpty else { return }
        isBiometricEnabled = BiometricAuthManager.shared.isBiometricEnabled(forAccount: pk)
        biometricSwitch.isOn = isBiometricEnabled
    }

    private func showBiometricPasswordPrompt() {
        let biometric = BiometricAuthManager.shared
        let alert = UIAlertController(
            title: "Enable \(biometric.biometricName)",
            message: "Enter your password to securely save it for \(biometric.biometricName) unlock.",
            preferredStyle: .alert
        )
        alert.addTextField { field in
            field.placeholder = "Password"
            field.isSecureTextEntry = true
        }
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [weak self] _ in
            self?.biometricSwitch.setOn(false, animated: true)
            self?.isBiometricEnabled = false
        })
        alert.addAction(UIAlertAction(title: "Enable", style: .default) { [weak self] _ in
            let password = alert.textFields?.first?.text ?? ""
            self?.enableBiometric(password: password)
        })
        present(alert, animated: true)
    }

    private func enableBiometric(password: String) {
        guard !password.isEmpty else {
            biometricSwitch.setOn(false, animated: true)
            isBiometricEnabled = false
            return
        }

        let pk = viewModel.publicKey
        Task {
            do {
                _ = try await AccountManager.shared.unlock(password: password)
                let biometric = BiometricAuthManager.shared
                try biometric.savePassword(password, forAccount: pk)
                biometric.setBiometricEnabled(true, forAccount: pk)
                isBiometricEnabled = true
                biometricSwitch.setOn(true, animated: true)
            } catch {
                isBiometricEnabled = false
                biometricSwitch.setOn(false, animated: true)
                let alert = UIAlertController(title: "Error", message: "Wrong password", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default))
                present(alert, animated: true)
            }
        }
    }

    private func disableBiometric() {
        let pk = viewModel.publicKey
        let biometric = BiometricAuthManager.shared
        biometric.deletePassword(forAccount: pk)
        biometric.setBiometricEnabled(false, forAccount: pk)
        isBiometricEnabled = false
    }
}

// MARK: - Settings Profile Edit Screen

/// Stateful edit screen used by UIKit settings flow.
/// Restores toolbar (Cancel/Done) and save behavior expected by ProfileEditView.
private struct SettingsProfileEditScreen: View {
    let onAddAccount: ((AuthScreen) -> Void)?
    let initialDisplayName: String
    let initialUsername: String
    let publicKey: String
    let onExit: () -> Void

    @Environment(\.dismiss) private var dismiss

    @State private var displayName: String
    @State private var username: String
    @State private var displayNameError: String?
    @State private var usernameError: String?
    @State private var pendingPhoto: UIImage?
    @State private var isSaving = false
    @State private var resultHandlerId: UUID?
    @State private var saveTimeoutTask: Task<Void, Never>?
    @State private var didNotifyExit = false

    init(
        onAddAccount: ((AuthScreen) -> Void)?,
        initialDisplayName: String,
        initialUsername: String,
        publicKey: String,
        onExit: @escaping () -> Void
    ) {
        self.onAddAccount = onAddAccount
        self.initialDisplayName = initialDisplayName
        self.initialUsername = initialUsername
        self.publicKey = publicKey
        self.onExit = onExit

        _displayName = State(initialValue: initialDisplayName)
        _username = State(initialValue: initialUsername)
    }

    var body: some View {
        GeometryReader { geometry in
            let safeTop = geometry.safeAreaInsets.top

            ZStack(alignment: .top) {
                RosettaColors.Adaptive.background
                    .ignoresSafeArea()

                ScrollView(.vertical, showsIndicators: false) {
                    ProfileEditView(
                        onAddAccount: onAddAccount,
                        displayName: $displayName,
                        username: $username,
                        publicKey: publicKey,
                        displayNameError: $displayNameError,
                        usernameError: $usernameError,
                        pendingPhoto: $pendingPhoto
                    )
                    .padding(.top, safeTop + 50)
                }

                toolbar(safeTop: safeTop)
            }
        }
        .toolbar(.hidden, for: .navigationBar)
        .onDisappear {
            cleanupPendingResultHandler()
            notifyExitIfNeeded()
        }
    }

    private var hasProfileChanges: Bool {
        displayName != initialDisplayName
            || username != initialUsername
            || pendingPhoto != nil
    }

    @ViewBuilder
    private func toolbar(safeTop: CGFloat) -> some View {
        HStack {
            Button {
                if isSaving {
                    cleanupPendingResultHandler()
                    isSaving = false
                }
                pendingPhoto = nil
                dismiss()
            } label: {
                Text("Cancel")
                    .font(.system(size: 17, weight: .medium))
                    .foregroundStyle(RosettaColors.Adaptive.text)
                    .frame(height: 44)
                    .padding(.horizontal, 10)
            }
            .buttonStyle(.plain)
            .glassCapsule()

            Spacer()

            Button {
                saveProfile()
            } label: {
                Text("Done")
                    .font(.system(size: 17, weight: .semibold))
                    .foregroundStyle(
                        hasProfileChanges
                            ? RosettaColors.Adaptive.text
                            : RosettaColors.Adaptive.text.opacity(0.4)
                    )
                    .frame(height: 44)
                    .padding(.horizontal, 10)
            }
            .buttonStyle(.plain)
            .glassCapsule()
            .disabled(isSaving)
        }
        .padding(.horizontal, 15)
        .padding(.top, safeTop)
        .frame(maxWidth: .infinity)
        .frame(height: safeTop + 44)
    }

    private func saveProfile() {
        let trimmedName = displayName.trimmingCharacters(in: .whitespaces)
        let trimmedUsername = username.trimmingCharacters(in: .whitespaces).lowercased()

        if let error = ProfileValidator.validateDisplayName(trimmedName) {
            displayNameError = error.errorDescription
            return
        }
        if let error = ProfileValidator.validateUsername(trimmedUsername) {
            usernameError = error.errorDescription
            return
        }
        displayNameError = nil
        usernameError = nil

        guard hasProfileChanges else {
            dismiss()
            return
        }

        let hasTextChanges = trimmedName != initialDisplayName
            || trimmedUsername != initialUsername

        if !hasTextChanges {
            commitPendingAvatar()
            dismiss()
            return
        }

        guard !isSaving else { return }
        isSaving = true

        let handlerId = ProtocolManager.shared.addResultHandler { result in
            Task { @MainActor in
                guard isSaving else { return }
                cleanupPendingResultHandler()
                isSaving = false

                if result.resultCode == ResultCode.usernameTaken.rawValue {
                    usernameError = "This username is already taken"
                } else {
                    updateLocalProfile(displayName: trimmedName, username: trimmedUsername)
                    commitPendingAvatar()
                    dismiss()
                }
            }
        }
        resultHandlerId = handlerId

        if let hash = SessionManager.shared.privateKeyHash {
            var packet = PacketUserInfo()
            packet.username = trimmedUsername
            packet.title = trimmedName
            packet.privateKey = hash
            ProtocolManager.shared.sendPacket(packet)
        } else {
            // No server auth hash available — timeout fallback below will save locally.
        }

        saveTimeoutTask?.cancel()
        saveTimeoutTask = Task { @MainActor in
            try? await Task.sleep(nanoseconds: 10_000_000_000)
            guard !Task.isCancelled else { return }
            guard isSaving else { return }

            cleanupPendingResultHandler()
            isSaving = false
            updateLocalProfile(displayName: trimmedName, username: trimmedUsername)
            commitPendingAvatar()
            dismiss()
        }
    }

    private func cleanupPendingResultHandler() {
        if let id = resultHandlerId {
            ProtocolManager.shared.removeResultHandler(id)
            resultHandlerId = nil
        }
        saveTimeoutTask?.cancel()
        saveTimeoutTask = nil
    }

    private func commitPendingAvatar() {
        guard let photo = pendingPhoto else { return }
        AvatarRepository.shared.saveAvatar(publicKey: publicKey, image: photo)
        pendingPhoto = nil
    }

    private func updateLocalProfile(displayName: String, username: String) {
        AccountManager.shared.updateProfile(
            displayName: displayName,
            username: username
        )
        SessionManager.shared.updateDisplayNameAndUsername(
            displayName: displayName,
            username: username
        )
    }

    private func notifyExitIfNeeded() {
        guard !didNotifyExit else { return }
        didNotifyExit = true
        onExit()
    }
}

// MARK: - SwiftUI Edit Button (needed for @MainActor closure compatibility)

private struct SettingsEditButton: View {
    let action: @MainActor () -> Void

    var body: some View {
        Button(action: action) {
            Text("Edit")
                .font(.system(size: 17, weight: .medium))
                .foregroundStyle(RosettaColors.Adaptive.text)
                .frame(height: 44)
                .padding(.horizontal, 10)
        }
        .buttonStyle(.plain)
        .glassCapsule()
    }
}

// MARK: - SwiftUI Bridge

struct SettingsContainerView: UIViewControllerRepresentable {
    var onLogout: (() -> Void)?
    var onAddAccount: ((AuthScreen) -> Void)?
    @Binding var isEditingProfile: Bool
    @Binding var isDetailPresented: Bool

    func makeUIViewController(context: Context) -> UINavigationController {
        let vc = SettingsViewController()
        vc.onLogout = onLogout
        vc.onAddAccount = onAddAccount
        vc.onEditingStateChanged = { editing in
            DispatchQueue.main.async { isEditingProfile = editing }
        }
        vc.onDetailStateChanged = { detail in
            DispatchQueue.main.async { isDetailPresented = detail }
        }
        let nav = UINavigationController(rootViewController: vc)
        nav.setNavigationBarHidden(true, animated: false)
        nav.view.backgroundColor = UIColor(RosettaColors.Adaptive.background)
        return nav
    }

    func updateUIViewController(_ nav: UINavigationController, context: Context) {
        // State flows from UIKit → SwiftUI via callbacks, not the other way
    }
}
