import SwiftUI

// MARK: - Settings Navigation

enum SettingsDestination: Hashable {
    case updates
    case safety
    case backup
    case appearance
}

/// Settings screen with in-place profile editing transition.
/// Avatar stays in place, content fades between settings and edit modes,
/// tab bar slides down when editing.
struct SettingsView: View {
    var onLogout: (() -> Void)?
    var onAddAccount: ((AuthScreen) -> Void)?
    @Binding var isEditingProfile: Bool
    @Binding var isDetailPresented: Bool

    @StateObject private var viewModel = SettingsViewModel()
    @State private var navigationPath = NavigationPath()
    @State private var showDeleteAccountConfirmation = false
    @State private var showAddAccountSheet = false

    // Biometric
    @State private var isBiometricEnabled = false
    @State private var showBiometricPasswordPrompt = false
    @State private var biometricPassword = ""
    @State private var biometricError: String?

    // Avatar
    @State private var avatarImage: UIImage?
    /// Photo selected in ProfileEditView but not yet committed — saved on Done press.
    @State private var pendingAvatarPhoto: UIImage?

    // Edit mode field state — initialized when entering edit mode
    @State private var editDisplayName = ""
    @State private var editUsername = ""
    @State private var displayNameError: String?
    @State private var usernameError: String?
    @State private var isSaving = false
    @State private var viewSafeArea: EdgeInsets = EdgeInsets()

    var body: some View {
        ZStack(alignment: .top) {
            NavigationStack(path: $navigationPath) {
                GeometryReader { geometry in
                    let size = geometry.size
                    let safeArea = geometry.safeAreaInsets

                    settingsScrollContent(size: size, safeArea: safeArea)
                        .ignoresSafeArea()
                        .onAppear { viewSafeArea = safeArea }
                }
                .toolbar(.hidden, for: .navigationBar)
            .navigationDestination(for: SettingsDestination.self) { destination in
                switch destination {
                case .updates:
                    UpdatesView()
                case .safety:
                    SafetyView(onLogout: onLogout)
                case .backup:
                    BackupView()
                case .appearance:
                    AppearanceViewRepresentable()
                }
            }
            .task {
                viewModel.refresh()
                refreshBiometricState()
                avatarImage = AvatarRepository.shared.loadAvatar(publicKey: viewModel.publicKey)
            }
            .alert("Delete Account", isPresented: $showDeleteAccountConfirmation) {
                Button("Cancel", role: .cancel) {}
                Button("Delete Account", role: .destructive) {
                    let publicKey = SessionManager.shared.currentPublicKey
                    BiometricAuthManager.shared.clearAll(forAccount: publicKey)
                    AvatarRepository.shared.removeAvatar(publicKey: publicKey)
                    // Start fade overlay FIRST — covers the screen before
                    // deleteAccount() triggers setActiveAccount(next) which
                    // would cause MainTabView .id() recreation.
                    onLogout?()
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.04) {
                        DialogRepository.shared.reset(clearPersisted: true)
                        MessageRepository.shared.reset(clearPersisted: true)
                        let defaults = UserDefaults.standard
                        defaults.removeObject(forKey: "rosetta_recent_searches_\(publicKey)")
                        defaults.removeObject(forKey: "rosetta_last_sync_\(publicKey)")
                        defaults.removeObject(forKey: "backgroundBlurColor_\(publicKey)")
                        SessionManager.shared.endSession()
                        try? AccountManager.shared.deleteAccount()
                    }
                }
            } message: {
                Text("Are you sure? This will permanently delete your account from this device. You'll need your seed phrase to recover it.")
            }
            .onChange(of: isEditingProfile) { _, isEditing in
                if !isEditing {
                    viewModel.refresh()
                    refreshBiometricState()
                    avatarImage = AvatarRepository.shared.loadAvatar(publicKey: viewModel.publicKey)
                }
            }
            .onAppear { refreshBiometricState() }
            .onReceive(NotificationCenter.default.publisher(for: .profileDidUpdate)) { _ in
                viewModel.refresh()
            }
            .alert(
                "Enable \(BiometricAuthManager.shared.biometricName)",
                isPresented: $showBiometricPasswordPrompt
            ) {
                SecureField("Password", text: $biometricPassword)
                Button("Cancel", role: .cancel) {
                    biometricPassword = ""
                    biometricError = nil
                    isBiometricEnabled = false
                }
                Button("Enable") { enableBiometric() }
            } message: {
                if let biometricError {
                    Text(biometricError)
                } else {
                    Text("Enter your password to securely save it for \(BiometricAuthManager.shared.biometricName) unlock.")
                }
            }
            .onChange(of: navigationPath.count) { _, newCount in
                isDetailPresented = newCount > 0
            }
            .confirmationDialog(
                "Create account",
                isPresented: $showAddAccountSheet,
                titleVisibility: .visible
            ) {
                Button("Create New Account") {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
                        onAddAccount?(.seedPhrase)
                    }
                }
                Button("Import Existing Account") {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
                        onAddAccount?(.importSeed)
                    }
                }
                Button("Cancel", role: .cancel) {}
            } message: {
                Text("You may create a new account or import an existing one.")
            }
        }

            // Toolbar OUTSIDE NavigationStack — sits in safe area naturally
            if !isDetailPresented {
                HStack {
                    if isEditingProfile {
                        Button {
                            pendingAvatarPhoto = nil
                            withAnimation(.easeInOut(duration: 0.2)) {
                                isEditingProfile = false
                            }
                        } label: {
                            Text("Cancel")
                                .font(.system(size: 17, weight: .medium))
                                .foregroundStyle(RosettaColors.Adaptive.text)
                                .frame(height: 44)
                                .padding(.horizontal, 10)
                        }
                        .buttonStyle(.plain)
                        .glassCapsule()
                        .disabled(isSaving)
                    } else {
                        DarkModeButton()
                            .glassCircle()
                    }

                    Spacer()

                    if isEditingProfile {
                        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()
                    } else {
                        Button {
                            editDisplayName = viewModel.displayName
                            editUsername = viewModel.username
                            displayNameError = nil
                            usernameError = nil
                            pendingAvatarPhoto = nil
                            withAnimation(.easeInOut(duration: 0.2)) {
                                isEditingProfile = true
                            }
                        } label: {
                            Text("Edit")
                                .font(.system(size: 17, weight: .medium))
                                .foregroundStyle(RosettaColors.Adaptive.text)
                                .frame(height: 44)
                                .padding(.horizontal, 10)
                        }
                        .buttonStyle(.plain)
                        .glassCapsule()
                    }
                }
                .padding(.horizontal, 15)
            }
        }
    }

    // MARK: - Scroll Content (reference: Home.swift structure)

    /// Main scrollable content with metaball Canvas — matches reference exactly.
    @ViewBuilder
    private func settingsScrollContent(size: CGSize, safeArea: EdgeInsets) -> some View {
        let isHavingNotch = safeArea.bottom != 0
        ScrollView(.vertical, showsIndicators: false) {
            if isEditingProfile {
                ProfileEditView(
                    onAddAccount: onAddAccount,
                    displayName: $editDisplayName,
                    username: $editUsername,
                    publicKey: viewModel.publicKey,
                    displayNameError: $displayNameError,
                    usernameError: $usernameError,
                    pendingPhoto: $pendingAvatarPhoto
                )
                .transition(.opacity)
                .padding(.top, safeArea.top + 50)
            } else {
                settingsContentInner(safeArea: safeArea, screenWidth: size.width)
                    .transition(.opacity)
            }
        }
        .coordinateSpace(name: "SETTINGS_SCROLL")
    }

    // MARK: - Toolbar Overlay (replaces NavigationStack toolbar)

    @ViewBuilder
    private func settingsToolbarOverlay(safeArea: EdgeInsets) -> some View {
        HStack {
            if isEditingProfile {
                Button {
                    pendingAvatarPhoto = nil
                    withAnimation(.easeInOut(duration: 0.2)) {
                        isEditingProfile = false
                    }
                } label: {
                    Text("Cancel")
                        .font(.system(size: 17, weight: .medium))
                        .foregroundStyle(RosettaColors.Adaptive.text)
                        .frame(height: 44)
                        .padding(.horizontal, 10)
                }
                .buttonStyle(.plain)
                .glassCapsule()
                .disabled(isSaving)
            } else {
                DarkModeButton()
                    .glassCircle()
            }

            Spacer()

            if isEditingProfile {
                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()
            } else {
                Button {
                    editDisplayName = viewModel.displayName
                    editUsername = viewModel.username
                    displayNameError = nil
                    usernameError = nil
                    pendingAvatarPhoto = nil
                    withAnimation(.easeInOut(duration: 0.2)) {
                        isEditingProfile = true
                    }
                } label: {
                    Text("Edit")
                        .font(.system(size: 17, weight: .medium))
                        .foregroundStyle(RosettaColors.Adaptive.text)
                        .frame(height: 44)
                        .padding(.horizontal, 10)
                }
                .buttonStyle(.plain)
                .glassCapsule()
            }
        }
        .padding(.horizontal, 15)
        .padding(.top, safeArea.top)
        .frame(maxWidth: .infinity)
        .frame(height: safeArea.top + 44)
    }

    // MARK: - Profile Save

    private var hasProfileChanges: Bool {
        editDisplayName != viewModel.displayName
            || editUsername != viewModel.username
            || pendingAvatarPhoto != nil
    }

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

        // Validate before saving
        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 {
            withAnimation(.easeInOut(duration: 0.2)) {
                isEditingProfile = false
            }
            return
        }

        let hasTextChanges = trimmedName != viewModel.displayName
            || trimmedUsername != viewModel.username

        // Avatar-only change — save locally, no server round-trip needed
        if !hasTextChanges {
            commitPendingAvatar()
            withAnimation(.easeInOut(duration: 0.2)) {
                isEditingProfile = false
            }
            return
        }

        guard !isSaving else { return }
        isSaving = true

        // Register one-shot result handler (Android parity: waitPacket(0x02))
        let handlerId = ProtocolManager.shared.addResultHandler { result in
            Task { @MainActor in
                guard isSaving else { return }
                isSaving = false

                if result.resultCode == ResultCode.usernameTaken.rawValue {
                    usernameError = "This username is already taken"
                } else {
                    // Server confirmed OR unknown code — save locally.
                    // PacketResult has no request ID, so we can't guarantee this
                    // response belongs to our PacketUserInfo. Treat non-usernameTaken
                    // as success and save locally (desktop parity: fallback save).
                    updateLocalProfile(displayName: trimmedName, username: trimmedUsername)
                    commitPendingAvatar()
                    withAnimation(.easeInOut(duration: 0.2)) {
                        isEditingProfile = false
                    }
                }
            }
        }

        // Send PacketUserInfo to server
        if let hash = SessionManager.shared.privateKeyHash {
            var packet = PacketUserInfo()
            packet.username = trimmedUsername
            packet.title = trimmedName
            packet.privateKey = hash
            ProtocolManager.shared.sendPacket(packet)
        }

        // 10s timeout — fallback to local save (Android parity)
        Task { @MainActor in
            try? await Task.sleep(nanoseconds: 10_000_000_000)
            guard isSaving else { return }
            // Server didn't respond — save locally as fallback
            ProtocolManager.shared.removeResultHandler(handlerId)
            isSaving = false
            updateLocalProfile(displayName: trimmedName, username: trimmedUsername)
            commitPendingAvatar()
            withAnimation(.easeInOut(duration: 0.2)) {
                isEditingProfile = false
            }
        }
    }

    /// Saves pending avatar photo to disk and updates the displayed avatar.
    private func commitPendingAvatar() {
        if let photo = pendingAvatarPhoto {
            AvatarRepository.shared.saveAvatar(publicKey: viewModel.publicKey, image: photo)
            avatarImage = photo
            pendingAvatarPhoto = nil
        }
    }

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

    // MARK: - Settings Content

    @ViewBuilder
    private func settingsContentInner(safeArea: EdgeInsets, screenWidth: CGFloat) -> some View {
        let isHavingNotch = safeArea.bottom != 0
        VStack(spacing: 0) {
            SettingsProfileHeader(
                viewModel: viewModel,
                avatarImage: avatarImage,
                safeArea: safeArea,
                isHavingNotch: isHavingNotch,
                screenWidth: screenWidth
            )

            accountSwitcherCard

            // Desktop parity: separate cards with subtitle descriptions.
            appearanceCard
            updatesCard
            if BiometricAuthManager.shared.isBiometricAvailable {
                biometricCard
            }
            safetyCard

            rosettaPowerFooter
        }
        .padding(.horizontal, 16)
        .padding(.top, 0)
        .padding(.bottom, 300)
    }

    /// Desktop parity: "rosetta — powering freedom" footer with small R icon.
    private var rosettaPowerFooter: some View {
        HStack(spacing: 6) {
            RosettaLogoShape()
                .fill(RosettaColors.Adaptive.textTertiary)
                .frame(width: 11, height: 11)

            Text("rosetta – powering freedom")
                .font(.system(size: 12))
                .foregroundStyle(RosettaColors.Adaptive.textTertiary)
        }
        .frame(maxWidth: .infinity)
        .padding(.top, 32)
    }

    // MARK: - Account Switcher Card

    @State private var accountToDelete: Account?
    @State private var showDeleteAccountSheet = false

    private var accountSwitcherCard: some View {
        let currentKey = AccountManager.shared.currentAccount?.publicKey
        let otherAccounts = AccountManager.shared.allAccounts.filter { $0.publicKey != currentKey }

        return SettingsCard {
            VStack(spacing: 0) {
                ForEach(Array(otherAccounts.enumerated()), id: \.element.publicKey) { index, account in
                    let position: SettingsRowPosition = index == 0 && otherAccounts.count == 1
                        ? .top
                        : index == 0 ? .top : .middle

                    accountRow(account, position: position)

                    Divider()
                        .background(RosettaColors.Adaptive.divider)
                        .padding(.leading, 52)
                }

                addAccountRow(position: otherAccounts.isEmpty ? .alone : .bottom)
            }
        }
        .padding(.top, 16)
        .confirmationDialog(
            "Are you sure you want to delete this account from this device?",
            isPresented: $showDeleteAccountSheet,
            titleVisibility: .visible
        ) {
            Button("Delete", role: .destructive) {
                if let acc = accountToDelete {
                    deleteOtherAccount(acc)
                    accountToDelete = nil
                }
            }
        }
    }

    private func accountRow(_ account: Account, position: SettingsRowPosition) -> some View {
        let name = account.displayName ?? String(account.publicKey.prefix(7))
        let initials = RosettaColors.initials(name: name, publicKey: account.publicKey)
        let colorIndex = RosettaColors.avatarColorIndex(for: name, publicKey: account.publicKey)
        let avatarImage = AvatarRepository.shared.loadAvatar(publicKey: account.publicKey)
        let unread = totalUnreadCount(for: account.publicKey)

        return AccountSwipeRow(
            position: position,
            onTap: {
                onLogout?()
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.04) {
                    AccountManager.shared.setActiveAccount(publicKey: account.publicKey)
                    SessionManager.shared.endSession()
                }
            },
            onDelete: {
                accountToDelete = account
                showDeleteAccountSheet = true
            }
        ) {
            HStack(spacing: 12) {
                AvatarView(
                    initials: initials,
                    colorIndex: colorIndex,
                    size: 30,
                    isSavedMessages: false,
                    image: avatarImage
                )

                Text(name)
                    .font(.system(size: 17, weight: .bold))
                    .foregroundStyle(RosettaColors.Adaptive.text)
                    .lineLimit(1)

                Spacer(minLength: 8)

                if unread > 0 {
                    Text(formattedUnreadCount(unread))
                        .font(.system(size: 13, weight: .semibold))
                        .foregroundStyle(.white)
                        .padding(.horizontal, 8)
                        .padding(.vertical, 3)
                        .background(RosettaColors.primaryBlue)
                        .clipShape(Capsule())
                }
            }
            .padding(.horizontal, 16)
            .frame(height: 48)
        }
    }

    private func addAccountRow(position: SettingsRowPosition) -> some View {
        Button {
            showAddAccountSheet = true
        } label: {
            HStack(spacing: 12) {
                Image(systemName: "plus")
                    .font(.system(size: 16, weight: .medium))
                    .foregroundStyle(RosettaColors.primaryBlue)
                    .frame(width: 30, height: 30)

                Text("Add Account")
                    .font(.system(size: 17, weight: .medium))
                    .foregroundStyle(RosettaColors.primaryBlue)

                Spacer()
            }
            .padding(.horizontal, 16)
            .frame(height: 48)
            .contentShape(Rectangle())
        }
        .buttonStyle(.plain)
        .settingsHighlight(position: position)
    }

    /// Calculates total unread count for the given account's dialogs.
    /// Only returns meaningful data for the currently active session.
    /// Deletes another (non-active) account from the device.
    private func deleteOtherAccount(_ 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)
    }

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

    /// Formats unread count: "42" for < 1000, "1,2K" for >= 1000.
    private func formattedUnreadCount(_ count: Int) -> String {
        if count < 1000 {
            return "\(count)"
        }
        let thousands = Double(count) / 1000.0
        let formatted = String(format: "%.1f", thousands)
            .replacingOccurrences(of: ".", with: ",")
        return "\(formatted)K"
    }

    // MARK: - Desktop Parity Cards

    private var appearanceCard: some View {
        VStack(alignment: .leading, spacing: 8) {
            SettingsCard {
                NavigationLink(value: SettingsDestination.appearance) {
                    settingsRowLabel(
                        icon: "paintbrush.fill",
                        title: "Appearance",
                        color: .blue
                    )
                }
                .settingsHighlight()
            }
            Text("Customize theme, wallpaper and chat appearance.")
                .font(.system(size: 13))
                .foregroundStyle(RosettaColors.Adaptive.textSecondary)
                .padding(.horizontal, 16)
                .padding(.bottom, 8)
        }
        .padding(.top, 16)
    }

    private var updatesCard: some View {
        VStack(alignment: .leading, spacing: 8) {
            SettingsCard {
                NavigationLink(value: SettingsDestination.updates) {
                    settingsRowLabel(
                        icon: "arrow.triangle.2.circlepath",
                        title: "Updates",
                        color: .green
                    )
                }
                .settingsHighlight()
            }
            Text("You can check for new versions of the app here. Updates may include security improvements and new features.")
                .font(.system(size: 13))
                .foregroundStyle(RosettaColors.Adaptive.textSecondary)
                .padding(.horizontal, 16)
                .padding(.bottom, 8)
        }
        .padding(.top, 16)
    }

    private var safetyCard: some View {
        VStack(alignment: .leading, spacing: 8) {
            SettingsCard {
                NavigationLink(value: SettingsDestination.safety) {
                    settingsRowLabel(
                        icon: "shield.lefthalf.filled",
                        title: "Safety",
                        color: .purple
                    )
                }
                .settingsHighlight()
            }
            (
                Text("You can learn more about your safety on the safety page, please make sure you are viewing the screen alone ")
                    .foregroundStyle(RosettaColors.Adaptive.textSecondary)
                + Text("before proceeding to the safety page")
                    .bold()
                    .foregroundStyle(RosettaColors.Adaptive.text)
                + Text(".")
                    .foregroundStyle(RosettaColors.Adaptive.textSecondary)
            )
            .font(.system(size: 13))
            .padding(.horizontal, 16)
            .padding(.bottom, 8)
        }
        .padding(.top, 16)
    }

    private var logoutCard: some View {
        settingsCardWithSubtitle(
            icon: "rectangle.portrait.and.arrow.right",
            title: "Logout",
            color: RosettaColors.error,
            titleColor: RosettaColors.error,
            showChevron: false,
            subtitle: "Logging out of your account. After logging out, you will be redirected to the password entry page."
        ) {
            SessionManager.shared.endSession()
            onLogout?()
        }
    }

    // MARK: - Biometric Card

    private var biometricCard: some View {
        let biometric = BiometricAuthManager.shared

        return VStack(alignment: .leading, spacing: 8) {
            SettingsCard {
                settingsToggle(
                    icon: biometric.biometricIconName,
                    title: biometric.biometricName,
                    color: .blue,
                    isOn: isBiometricEnabled
                ) { newValue in
                    if newValue {
                        // Show password prompt to enable
                        biometricPassword = ""
                        biometricError = nil
                        showBiometricPasswordPrompt = true
                    } else {
                        disableBiometric()
                    }
                }
            }
            Text("Use \(biometric.biometricName) to unlock Rosetta instead of entering your password.")
                .font(.system(size: 13))
                .foregroundStyle(RosettaColors.Adaptive.textSecondary)
                .padding(.horizontal, 16)
                .padding(.bottom, 8)
        }
        .padding(.top, 16)
    }

    /// Toggle row for settings (icon + title + Toggle).
    private func settingsToggle(
        icon: String,
        title: String,
        color: Color,
        isOn: Bool,
        action: @escaping (Bool) -> Void
    ) -> some View {
        HStack(spacing: 0) {
            Image(systemName: icon)
                .font(.system(size: 16))
                .foregroundStyle(.white)
                .frame(width: 26, height: 26)
                .background(color)
                .clipShape(RoundedRectangle(cornerRadius: 6))
                .padding(.trailing, 16)

            Text(title)
                .font(.system(size: 17, weight: .medium))
                .tracking(-0.43)
                .foregroundStyle(RosettaColors.Adaptive.text)
                .lineLimit(1)

            Spacer(minLength: 8)

            Toggle("", isOn: Binding(
                get: { isOn },
                set: { action($0) }
            ))
            .labelsHidden()
            .tint(RosettaColors.primaryBlue)
        }
        .padding(.horizontal, 16)
        .frame(height: 52)
    }

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

    private func enableBiometric() {
        let enteredPassword = biometricPassword
        biometricPassword = ""

        guard !enteredPassword.isEmpty else {
            biometricError = "Password cannot be empty"
            isBiometricEnabled = false
            return
        }

        let publicKey = viewModel.publicKey

        Task {
            do {
                // Verify password is correct by attempting unlock
                _ = try await AccountManager.shared.unlock(password: enteredPassword)

                // Password correct — save for biometric
                let biometric = BiometricAuthManager.shared
                try biometric.savePassword(enteredPassword, forAccount: publicKey)
                biometric.setBiometricEnabled(true, forAccount: publicKey)
                isBiometricEnabled = true
                biometricError = nil
            } catch {
                isBiometricEnabled = false
                biometricError = "Wrong password"
                showBiometricPasswordPrompt = true
            }
        }
    }

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

    // MARK: - Danger Section

    private var dangerSection: some View {
        SettingsCard {
            Button {
                showDeleteAccountConfirmation = true
            } label: {
                HStack {
                    Spacer()
                    Text("Delete Account")
                        .font(.system(size: 17))
                        .foregroundStyle(RosettaColors.error)
                    Spacer()
                }
                .frame(height: 52)
                .contentShape(Rectangle())
            }
            .settingsHighlight()
        }
    }

    // MARK: - Debug (stress test)

    #if DEBUG
    private var debugCard: some View {
        SettingsCard {
            Button {
                StressTestGenerator.generateMessages(count: 100, dialogKey: "stress_test_\(Int.random(in: 1000...9999))")
            } label: {
                HStack {
                    Spacer()
                    Text("🧪 Generate 100 Messages + Photos")
                        .font(.system(size: 17))
                        .foregroundStyle(.orange)
                    Spacer()
                }
                .frame(height: 52)
                .contentShape(Rectangle())
            }
            .settingsHighlight()
        }
    }
    #endif

    // MARK: - Helpers

    /// Figma row: 52pt height, 30×30 rounded icon (r7), 23pt symbol, Medium 17pt title.
    private func settingsRow(
        icon: String,
        title: String,
        color: Color,
        titleColor: Color = RosettaColors.Adaptive.text,
        detail: String? = nil,
        showChevron: Bool = true,
        action: @escaping () -> Void
    ) -> some View {
        Button(action: action) {
            settingsRowLabel(
                icon: icon, title: title, color: color,
                titleColor: titleColor, detail: detail,
                showChevron: showChevron
            )
        }
        .settingsHighlight()
    }

    /// Non-interactive row label for use inside NavigationLink.
    private func settingsRowLabel(
        icon: String,
        title: String,
        color: Color,
        titleColor: Color = RosettaColors.Adaptive.text,
        detail: String? = nil,
        showChevron: Bool = true
    ) -> some View {
        HStack(spacing: 0) {
            Image(systemName: icon)
                .font(.system(size: 16))
                .foregroundStyle(.white)
                .frame(width: 26, height: 26)
                .background(color)
                .clipShape(RoundedRectangle(cornerRadius: 6))
                .padding(.trailing, 16)

            Text(title)
                .font(.system(size: 17, weight: .medium))
                .tracking(-0.43)
                .foregroundStyle(titleColor)
                .lineLimit(1)

            Spacer(minLength: 8)

            if let detail {
                Text(detail)
                    .font(.system(size: 17))
                    .tracking(-0.43)
                    .foregroundStyle(RosettaColors.secondaryText)
            }

            if showChevron {
                Image(systemName: "chevron.right")
                    .font(.system(size: 14, weight: .semibold))
                    .foregroundStyle(RosettaColors.tertiaryText)
                    .frame(width: 8)
                    .padding(.leading, detail != nil ? 16 : 0)
            }
        }
        .padding(.horizontal, 16)
        .frame(height: 52)
        .contentShape(Rectangle())
    }

    /// Desktop parity: card with a single settings row + subtitle text below.
    private func settingsCardWithSubtitle(
        icon: String,
        title: String,
        color: Color,
        titleColor: Color = RosettaColors.Adaptive.text,
        showChevron: Bool = true,
        subtitle: String,
        action: @escaping () -> Void
    ) -> some View {
        VStack(alignment: .leading, spacing: 8) {
            SettingsCard {
                settingsRow(
                    icon: icon, title: title, color: color,
                    titleColor: titleColor, showChevron: showChevron,
                    action: action
                )
            }
            Text(subtitle)
                .font(.system(size: 13))
                .foregroundStyle(RosettaColors.Adaptive.textSecondary)
                .padding(.horizontal, 16)
                .padding(.bottom, 8)
        }
        .padding(.top, 16)
    }

    private var sectionDivider: some View {
        Divider()
            .background(RosettaColors.Adaptive.divider)
            .padding(.leading, 62)
    }

}

// MARK: - Account Swipe Row

/// Row with swipe-to-delete that doesn't conflict with tap action.
/// Uses a gesture-priority trick: horizontal DragGesture on a transparent overlay
/// takes priority only when horizontal movement exceeds vertical (swipe left).
/// Vertical drags and taps pass through to the content below.
private struct AccountSwipeRow<Content: View>: View {
    let position: SettingsRowPosition
    let onTap: () -> Void
    let onDelete: () -> Void
    @ViewBuilder let content: () -> Content

    @State private var swipeOffset: CGFloat = 0
    @State private var isRevealed = false
    private let deleteWidth: CGFloat = 80
    private let cardRadius: CGFloat = 12

    /// Top-right corner radius based on row position in the card.
    private var deleteTopRadius: CGFloat {
        switch position {
        case .top, .alone: return cardRadius
        default: return 0
        }
    }

    /// Bottom-right corner radius based on row position in the card.
    private var deleteBottomRadius: CGFloat {
        // Account rows are never .bottom — addAccountRow is always below.
        // But handle it for completeness.
        switch position {
        case .bottom, .alone: return cardRadius
        default: return 0
        }
    }

    var body: some View {
        GeometryReader { geo in
            ZStack(alignment: .trailing) {
                // Delete button behind — only when swiped
                if swipeOffset < -5 {
                    HStack(spacing: 0) {
                        Spacer()
                        Button {
                            withAnimation(.easeOut(duration: 0.2)) {
                                swipeOffset = 0
                                isRevealed = false
                            }
                            onDelete()
                        } label: {
                            Text("Delete")
                                .font(.system(size: 17, weight: .regular))
                                .foregroundStyle(.white)
                                .frame(width: deleteWidth, height: geo.size.height)
                                .background(
                                    UnevenRoundedRectangle(
                                        topLeadingRadius: 0,
                                        bottomLeadingRadius: 0,
                                        bottomTrailingRadius: deleteBottomRadius,
                                        topTrailingRadius: deleteTopRadius
                                    )
                                    .fill(Color.red)
                                )
                        }
                    }
                }

                // Content row
                content()
                    .contentShape(Rectangle())
                    .offset(x: swipeOffset)
                    .onTapGesture {
                        if isRevealed {
                            withAnimation(.easeOut(duration: 0.2)) {
                                swipeOffset = 0
                                isRevealed = false
                            }
                        } else {
                            onTap()
                        }
                    }
                    .highPriorityGesture(
                        DragGesture(minimumDistance: 20, coordinateSpace: .local)
                            .onChanged { value in
                                let dx = value.translation.width
                                let dy = value.translation.height
                                // Only respond to horizontal swipes
                                guard abs(dx) > abs(dy) else { return }

                                if isRevealed {
                                    // Already open — allow closing
                                    let newOffset = -deleteWidth + dx
                                    swipeOffset = max(min(newOffset, 0), -deleteWidth - 20)
                                } else if dx < 0 {
                                    // Swiping left to reveal
                                    swipeOffset = max(dx, -deleteWidth - 20)
                                }
                            }
                            .onEnded { value in
                                let dx = value.translation.width
                                guard abs(dx) > abs(value.translation.height) else {
                                    // Was vertical — snap back
                                    withAnimation(.easeOut(duration: 0.2)) {
                                        swipeOffset = isRevealed ? -deleteWidth : 0
                                    }
                                    return
                                }

                                withAnimation(.easeOut(duration: 0.2)) {
                                    if swipeOffset < -deleteWidth / 2 {
                                        swipeOffset = -deleteWidth
                                        isRevealed = true
                                    } else {
                                        swipeOffset = 0
                                        isRevealed = false
                                    }
                                }
                            }
                    )
            }
        }
        .frame(height: 48)
        .clipped()
    }
}
