//
//  TopUpView.swift
//  B24PaymentSdk
//
//  Created by visal ny on 25/12/24.
//

import UIKit
import Alamofire

private func debugLogRecentTransactions(_ transactions: [DWalletTransaction], context: String) {
    print("========== \(context) ==========")
    let encoder = JSONEncoder()
    encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
    for (index, transaction) in transactions.enumerated() {
        if let data = try? encoder.encode(transaction),
           let json = String(data: data, encoding: .utf8) {
            print("[\(index)] \(json)")
        } else {
            print("[\(index)] unable to encode transaction: \(transaction.tranID)")
        }
    }
    print("================================")
}

class TopUpView: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UITextFieldDelegate, UIGestureRecognizerDelegate, TransactionsViewDelegate {
    
    // Static flag to track top-up transactions
    public static var isTopUpTransaction: Bool = false

    // MARK: - Transaction Polling
    private var pollingTimer: Timer?
    private var isPolling: Bool = false
    private var isFetchingTransactions: Bool = false
    private var isFetchingBalance: Bool = false
    private let pollingInterval: TimeInterval = 10.0
    private var pollingRetryCount: Int = 0
    private let maxPollingRetries: Int = 30


    @IBOutlet weak var buttonSpaceBottom: NSLayoutConstraint!
    
    @IBOutlet weak var amountCollectionView: UICollectionView!
    
    @IBOutlet weak var contenContainer: UIView!
    @IBOutlet weak var TitleLabel: UILabel!
    @IBOutlet weak var walletNo: UILabel!
    @IBOutlet weak var line: UIView!
    @IBOutlet weak var balanceLabel: UILabel!
    @IBOutlet weak var amountLabel: UILabel!
    @IBOutlet weak var currencyLabel: UILabel!
    @IBOutlet weak var bottomView: UIView!
    @IBOutlet weak var chooseAmountLabel: UILabel!
    @IBOutlet weak var lineChooseAmount: UIView!
    @IBOutlet weak var inputAmount: UITextField!
    @IBOutlet weak var buttonOk: UIButton!
    
    var amountList:[String] = ["10","20","40","50","100","200"]

    let usdAmountList: [String] = ["10", "20", "40", "50", "100", "200"]
    let khrAmountList: [String] = ["10,000", "20,000", "40,000", "50,000", "100,000", "200,000"]
    var currentAmountList: [String] = []

    var defaultSelectedIndex: IndexPath = IndexPath(row: 0, section: 0) // Default item index

    var language:String?
    var walletId:String=""
    var walletName:String = ""
    var wallet: String = ""
    var balance: String = ""
    var currency: String = ""
    var currencyCode:String=""
    var currencySymbol:String=""
    
    var topUpAmount:String?
    
    let numberFormatter: NumberFormatter = {
            let formatter = NumberFormatter()
            formatter.numberStyle = .decimal
            formatter.groupingSeparator = "," // Optional: Change this if you need a different separator
            formatter.groupingSize = 3 // Optional: This is the default, which groups digits in sets of 3
            return formatter
        }()
    
    // MARK: - Pull-to-Refresh
    private let refreshControl = UIRefreshControl()

    // MARK: - Network Monitoring
    private var isWaitingForConnection: Bool = false

    // MARK: - Bottom Sheet Properties
    var transactionBottomSheet: TransactionsView?
    private weak var transactionDetailView: TransactionDetailView?
    private var initialBottomSheetY: CGFloat = 0
    private var currentDetentState: BottomSheetDetent = .medium
    private var isHandlingBottomSheetGesture: Bool = false
    private var lastHapticDetentState: BottomSheetDetent?
    private var startedOnGrip = false
    
    enum BottomSheetDetent {
        case medium
        case large
        
        func height(for screenHeight: CGFloat) -> CGFloat {
            switch self {
            case .medium:
                return screenHeight * 0.50
            case .large:
                return screenHeight * 0.90
            }
        }
        
        func yPosition(for screenHeight: CGFloat) -> CGFloat {
            return screenHeight - height(for: screenHeight)
        }
    }
    
    // MARK: - Recent Transaction Section
    private let recentTransactionContainer = UIView()
    private let recentTransactionHeader = UIView()
    private let recentTransactionLabel = UILabel()
    private let viewAllButton = UIButton(type: .system)
    private let recentTransactionPreview = UIStackView()
    private let recentTransactionLoader = UIActivityIndicatorView(style: .medium)
    private var loaderHeightConstraint: NSLayoutConstraint?
    private var recentTransactions: [DWalletTransaction] = []
    private var okButtonBottomConstraint: NSLayoutConstraint?
    private var cardGradientLayer: CAGradientLayer?
    private var hexagonLarge: CAShapeLayer?
    private var hexagonSmall: CAShapeLayer?
    
    // MARK: - Main Scroll View for global scrolling
    private let mainScrollView = UIScrollView()
    private let scrollContentView = UIView()


    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = DefaultAppearance.shared.screenBgColor
        
        getSharePref()
        
        keyboardHidden()
        
       
        // Set the current amount list based on currency
        updateAmountListForCurrency()

       
        B24PaymentSdkHelper.getCurrentLanguage(language: language)
        
        applyToolBar()
        
        inputAmount.delegate = self
        inputAmount.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)

        // Accessibility identifiers for XCUITest
        amountCollectionView.accessibilityIdentifier = "amountCollectionView"
        inputAmount.accessibilityIdentifier = "amountTextField"
        buttonOk.accessibilityIdentifier = "continueButton"
        balanceLabel.accessibilityIdentifier = "balanceLabel"
        
        setUpTopUI()
        setUpBottomUI()
        setUpColelctionView()
        
        
        //register keyboard
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWilldisplay), name:UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:UIResponder.keyboardWillHideNotification, object: nil)
        
        // Setup network monitoring
        
        // Setup main scroll view for global scrolling
        setupMainScrollView()
        setupRefreshControl()

    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        guard let gradientView = contenContainer.viewWithTag(1003) else { return }
        let bounds = gradientView.bounds
        guard bounds.width > 0 else { return }

        cardGradientLayer?.frame = bounds

        // Large hexagon: 120×120, top-right, partially off-card (top: -30, right: -30)
        let largeSize: CGFloat = 120
        let largeRect = CGRect(
            x: bounds.width - largeSize + 30,
            y: -30,
            width: largeSize,
            height: largeSize
        )
        hexagonLarge?.path = hexagonPath(in: largeRect).cgPath

        // Small hexagon: 80×80, bottom-right area (bottom: -20, right: 40)
        let smallSize: CGFloat = 80
        let smallRect = CGRect(
            x: bounds.width - smallSize - 40,
            y: bounds.height - smallSize + 20,
            width: smallSize,
            height: smallSize
        )
        hexagonSmall?.path = hexagonPath(in: smallRect).cgPath
    }

    /// Builds a regular hexagon UIBezierPath inside `rect`, matching CSS clip-path:
    /// polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)
    private func hexagonPath(in rect: CGRect) -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to:    CGPoint(x: rect.midX,        y: rect.minY))
        path.addLine(to: CGPoint(x: rect.maxX,        y: rect.minY + rect.height * 0.25))
        path.addLine(to: CGPoint(x: rect.maxX,        y: rect.minY + rect.height * 0.75))
        path.addLine(to: CGPoint(x: rect.midX,        y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.minX,        y: rect.minY + rect.height * 0.75))
        path.addLine(to: CGPoint(x: rect.minX,        y: rect.minY + rect.height * 0.25))
        path.close()
        return path
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return SDKVariableSetting.isDarkMode ? .lightContent : .darkContent
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        setNeedsStatusBarAppearanceUpdate()
        NetworkMonitor.shared.startMonitoring()
        fetchBalance()
        fetchRecentTransaction()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        stopPolling()
        NetworkMonitor.shared.stopMonitoring()
        NetworkMonitor.shared.onConnectionStatusChanged = nil
        isWaitingForConnection = false
        B24PaymentSdkHelper.removePersistentSnackbar(from: view)
    }

    deinit {
        pollingTimer?.invalidate()
    }
    
    // MARK: - Pull-to-Refresh Setup
    private func setupRefreshControl() {
        refreshControl.tintColor = DefaultAppearance.shared.primaryColor
        refreshControl.addTarget(self, action: #selector(refreshData), for: .valueChanged)
        mainScrollView.refreshControl = refreshControl
    }

    @objc private func refreshData() {
        fetchBalance()
        fetchRecentTransaction()
    }

    // MARK: - Network Monitoring Setup
    private func setupNetworkMonitoring() {
        NetworkMonitor.shared.onConnectionStatusChanged = { [weak self] isConnected in
            guard let self = self else { return }

            if isConnected {
                guard self.isWaitingForConnection else { return }

                self.isWaitingForConnection = false

                B24PaymentSdkHelper.hideNoInternetPopup(from: self)
                // Auto-refresh recent transactions when connection is restored
                self.fetchRecentTransaction()
            }
        }
    }
    
    // MARK: - Main Scroll View Setup
    private func setupMainScrollView() {
        // Configure scroll view
        mainScrollView.showsVerticalScrollIndicator = true
        mainScrollView.showsHorizontalScrollIndicator = false
        mainScrollView.translatesAutoresizingMaskIntoConstraints = false
        mainScrollView.backgroundColor = DefaultAppearance.shared.screenBgColor
        
        // Configure content view
        scrollContentView.translatesAutoresizingMaskIntoConstraints = false
        
        // Re-parent Storyboard views
        contenContainer.removeFromSuperview()
        bottomView.removeFromSuperview()
        
        // Build hierarchy
        view.addSubview(mainScrollView)
        mainScrollView.addSubview(scrollContentView)
        scrollContentView.addSubview(contenContainer)
        scrollContentView.addSubview(bottomView)
        
        // Sticky OK Button - ensure it's on top
        buttonOk.removeFromSuperview()
        view.addSubview(buttonOk)
        buttonOk.translatesAutoresizingMaskIntoConstraints = false
        
        okButtonBottomConstraint = buttonOk.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20)
        
        NSLayoutConstraint.activate([
            okButtonBottomConstraint!,
            buttonOk.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            buttonOk.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            buttonOk.heightAnchor.constraint(equalToConstant: 50)
        ])
        
        // Scroll view constraints - pin to main view and button
        NSLayoutConstraint.activate([
            mainScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            mainScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            mainScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            mainScrollView.bottomAnchor.constraint(equalTo: buttonOk.topAnchor, constant: -10)
        ])
        
        // Content view constraints - pin to scroll view guidelines
        NSLayoutConstraint.activate([
            scrollContentView.topAnchor.constraint(equalTo: mainScrollView.contentLayoutGuide.topAnchor),
            scrollContentView.leadingAnchor.constraint(equalTo: mainScrollView.contentLayoutGuide.leadingAnchor),
            scrollContentView.trailingAnchor.constraint(equalTo: mainScrollView.contentLayoutGuide.trailingAnchor),
            scrollContentView.bottomAnchor.constraint(equalTo: mainScrollView.contentLayoutGuide.bottomAnchor),
            scrollContentView.widthAnchor.constraint(equalTo: mainScrollView.frameLayoutGuide.widthAnchor)
        ])
        
        // Clear ALL existing storyboard height constraints from re-parented views
        [contenContainer, bottomView].forEach { container in
            container.constraints.forEach { constraint in
                if constraint.firstAttribute == .height {
                    constraint.isActive = false
                }
            }
        }
        
        // Top container layout
        contenContainer.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            contenContainer.topAnchor.constraint(equalTo: scrollContentView.topAnchor, constant: 30),
            contenContainer.leadingAnchor.constraint(equalTo: scrollContentView.leadingAnchor, constant: 20),
            contenContainer.trailingAnchor.constraint(equalTo: scrollContentView.trailingAnchor, constant: -20)
        ])
        
        // Bottom view layout
        bottomView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            bottomView.topAnchor.constraint(equalTo: contenContainer.bottomAnchor, constant: 20),
            bottomView.leadingAnchor.constraint(equalTo: scrollContentView.leadingAnchor),
            bottomView.trailingAnchor.constraint(equalTo: scrollContentView.trailingAnchor),
            bottomView.bottomAnchor.constraint(equalTo: scrollContentView.bottomAnchor, constant: -20)
        ])
        
        // Use UIStackView for robust interior layout of bottomView
        let bottomContentStack = UIStackView()
        bottomContentStack.axis = .vertical
        bottomContentStack.alignment = .fill
        bottomContentStack.distribution = .fill
        bottomContentStack.spacing = 15
        bottomContentStack.translatesAutoresizingMaskIntoConstraints = false
        bottomView.addSubview(bottomContentStack)
        
        NSLayoutConstraint.activate([
            bottomContentStack.topAnchor.constraint(equalTo: bottomView.topAnchor, constant: 10),
            bottomContentStack.leadingAnchor.constraint(equalTo: scrollContentView.leadingAnchor, constant: 20),
            bottomContentStack.trailingAnchor.constraint(equalTo: scrollContentView.trailingAnchor, constant: -20)
        ])
        
        // Thoroughly clear ALL existing storyboard constraints from bottomView items
        let bottomItems = [chooseAmountLabel, inputAmount, amountCollectionView]
        bottomView.constraints.forEach { constraint in
            let firstItem = constraint.firstItem
            let secondItem = constraint.secondItem
            
            let involvesBottomItems = bottomItems.contains { item in
                return (firstItem === item) || (secondItem === item)
            }
            
            if involvesBottomItems {
                constraint.isActive = false
            }
        }

        bottomItems.compactMap { $0 }.forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            $0.removeConstraints($0.constraints) 
            if let label = $0 as? UILabel {
                label.clipsToBounds = false
                label.setContentCompressionResistancePriority(.required, for: .vertical)
                label.setContentHuggingPriority(.required, for: .vertical)
            }
            bottomContentStack.addArrangedSubview($0)
        }
        
        // Remove lineChooseAmount from hierarchy
        lineChooseAmount?.removeFromSuperview()
        
        // Add recentTransactionContainer separately with explicit width constraints
        recentTransactionContainer.translatesAutoresizingMaskIntoConstraints = false
        bottomView.addSubview(recentTransactionContainer)
        
        // Add specific height constraints for views in the stack
        NSLayoutConstraint.activate([
            lineChooseAmount.heightAnchor.constraint(equalToConstant: 1),
            inputAmount.heightAnchor.constraint(equalToConstant: 55),
            amountCollectionView.heightAnchor.constraint(equalToConstant: 125),
            
            // Position recentTransactionContainer below the stack with same width as Continue button
            recentTransactionContainer.topAnchor.constraint(equalTo: bottomContentStack.bottomAnchor, constant: 10),
            recentTransactionContainer.leadingAnchor.constraint(equalTo: scrollContentView.leadingAnchor, constant: 20),
            recentTransactionContainer.trailingAnchor.constraint(equalTo: scrollContentView.trailingAnchor, constant: -20),
            recentTransactionContainer.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor, constant: -10)
        ])
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        if let text = textField.text {
            topUpAmount = text
            print("Amount after editing: \(topUpAmount)")
        }
        inputAmount.layer.borderColor = DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.15).cgColor
    }
    
    
    @objc func navigateToBill24Url() {
        B24PaymentSdkHelper.openDeeplink(deepLinkUrl: APIManager.openBill24Website(), view: self.view)
    }

    @objc func keyboardWillHide(){
        UIView.animate(withDuration: 0.3) {
            self.okButtonBottomConstraint?.constant = -20
            self.view.layoutIfNeeded()
        }
       
    }
    
    @objc func keyboardWilldisplay(notification:Notification){
        if let keyboardframe:NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue{
            let keyboardrectangle = keyboardframe.cgRectValue
            let keyboardHeight = keyboardrectangle.height
            
            UIView.animate(withDuration: 0.3) {
                let bottomPadding: CGFloat = 20
                self.okButtonBottomConstraint?.constant = -keyboardHeight + (self.view.safeAreaInsets.bottom > 0 ? self.view.safeAreaInsets.bottom : 0) - bottomPadding + 20
                self.okButtonBottomConstraint?.constant = -keyboardHeight + self.view.safeAreaInsets.bottom - 10
                self.view.layoutIfNeeded()
            }
        }
    }
    
    func keyboardHidden(){
        let tap = UITapGestureRecognizer(target: self, action: #selector(keyboardRemove))
        tap.cancelsTouchesInView = false
        tap.delegate = self
        self.view.addGestureRecognizer(tap)
    }
    
    @objc func keyboardRemove(){
        view.endEditing(true)
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField) {
        inputAmount.layer.borderColor = DefaultAppearance.shared.primaryColor.cgColor
    }

    private func normalizedAmountValue(from amountText: String) -> Decimal? {
        let sanitizedAmount = amountText.replacingOccurrences(of: ",", with: "")
        return Decimal(string: sanitizedAmount)
    }

    private func syncQuickSelectState(with amountText: String) {
        let matchedIndex = currentAmountList.firstIndex { presetAmount in
            normalizedAmountValue(from: presetAmount) == normalizedAmountValue(from: amountText)
        }

        let newSelectedIndex = matchedIndex.map { IndexPath(row: $0, section: 0) }
        let fallbackIndex = IndexPath(row: -1, section: -1)

        if let selectedIndexPaths = amountCollectionView.indexPathsForSelectedItems {
            for indexPath in selectedIndexPaths {
                if indexPath != newSelectedIndex {
                    amountCollectionView.deselectItem(at: indexPath, animated: true)
                }
            }
        }

        guard defaultSelectedIndex != (newSelectedIndex ?? fallbackIndex) else { return }

        defaultSelectedIndex = newSelectedIndex ?? fallbackIndex

        if let newSelectedIndex {
            amountCollectionView.selectItem(at: newSelectedIndex, animated: false, scrollPosition: [])
        }

        amountCollectionView.reloadData()
    }

    @objc func textFieldDidChange(_ textField: UITextField) {
        
        guard var currentText = textField.text else { return }

            if currency == "KHR" {
                // For KHR, allow only numeric characters (no decimals)
                currentText = currentText.replacingOccurrences(of: "[^0-9]", with: "", options: .regularExpression)
            } else {
                // Allow numbers and a single decimal point
                let regexPattern = "[^0-9.]"
                currentText = currentText.replacingOccurrences(of: regexPattern, with: "", options: .regularExpression)

                // Ensure only one decimal point is allowed and limit to 2 digits after decimal
                let components = currentText.components(separatedBy: ".")
                if components.count > 2 {
                    // Retain only the part before the first decimal point
                    currentText = components[0] + "." + components[1].prefix(2)
                } else if components.count == 2 {
                    // If there's already a decimal point, limit to 2 digits after the point
                    let integerPart = components[0]
                    let decimalPart = components[1].prefix(2) // Limit to 2 digits after decimal
                    currentText = integerPart + "." + decimalPart
                }
            }

            // If the input ends with a decimal point, allow it temporarily
            if currentText.last == "." {
                textField.text = currentText
                topUpAmount = currentText
                syncQuickSelectState(with: currentText)
                return
            }

            // Convert to a number for formatting
            if let number = Double(currentText) {
                textField.text = numberFormatter.string(from: NSNumber(value: number))
            } else {
                // Reset invalid or empty input
                textField.text = "0"
            }

            topUpAmount = textField.text
            syncQuickSelectState(with: textField.text ?? "0")
      
    }
    func getSharePref(){
        if let languageCode = SharedPreferenceManager.getString(forKey: SharePrefKey.lanuageCode.rawValue){
            language = languageCode
        }else{
            language = "km"
        }
        if let pmId = SharedPreferenceManager.getString(forKey: SharePrefKey.paymentMethodId.rawValue){
            walletId = pmId
        }else{
            walletId = ""
        }
        if let walletN = SharedPreferenceManager.getString(forKey: SharePrefKey.walletNo.rawValue){
            wallet = walletN
        }else{
            wallet = ""
        }
        if let amount = SharedPreferenceManager.getString(forKey: SharePrefKey.balance.rawValue){
            balance = amount
        }else{
            balance = ""
        }
        if let CurrencyCode = SharedPreferenceManager.getString(forKey: SharePrefKey.currency.rawValue){
            currency = CurrencyCode
        }else{
            currency = ""
        }
        
        if let name = SharedPreferenceManager.getString(forKey: SharePrefKey.walletName.rawValue){
            walletName =  name
        }else{
            walletName = ""
        }
        
    }
    
    
    private func applyToolBar(){
            // Configure navigation bar appearance for iOS 13+
            if #available(iOS 13.0, *) {
                let appearance = UINavigationBarAppearance()
                appearance.configureWithOpaqueBackground()
                appearance.backgroundColor = DefaultAppearance.shared.screenBgColor
                appearance.shadowColor = DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.3)
                
                navigationController?.navigationBar.standardAppearance = appearance
                navigationController?.navigationBar.scrollEdgeAppearance = appearance
                navigationController?.navigationBar.compactAppearance = appearance
            } else {
                navigationController?.navigationBar.barTintColor = DefaultAppearance.shared.screenBgColor
                navigationController?.navigationBar.isTranslucent = false
                navigationController?.navigationBar.shadowImage = UIImage()
            }
            
            navigationController?.navigationBar.tintColor = DefaultAppearance.shared.primaryLabelColor

            let customButton = UIButton(type: .custom)
            customButton.translatesAutoresizingMaskIntoConstraints = false
            customButton.tintColor = DefaultAppearance.shared.primaryLabelColor
            
            // Image
            let image = UIImage(systemName: "chevron.backward")?.withTintColor(DefaultAppearance.shared.primaryLabelColor, renderingMode: .alwaysOriginal)
            let imageView = UIImageView(image: image)
            imageView.contentMode = .scaleAspectFit
            imageView.translatesAutoresizingMaskIntoConstraints = false
            customButton.addSubview(imageView)
            
            // Add constraints for the back icon
            NSLayoutConstraint.activate([
                imageView.leadingAnchor.constraint(equalTo: customButton.leadingAnchor),
                imageView.trailingAnchor.constraint(equalTo: customButton.trailingAnchor),
                imageView.topAnchor.constraint(equalTo: customButton.topAnchor),
                imageView.bottomAnchor.constraint(equalTo: customButton.bottomAnchor),
                imageView.widthAnchor.constraint(equalToConstant: 24),
                imageView.heightAnchor.constraint(equalToConstant: 24)
            ])

            // Add action to the button
            customButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)

            // Create a UIBarButtonItem with the custom button
            let backButton = UIBarButtonItem(customView: customButton)
            navigationItem.leftBarButtonItem = backButton
            
            // Center title
            let titleLabel = UILabel()
            titleLabel.text = B24PaymentSdkHelper.localized(TopupLocalizedKeys.topup.rawValue)
            titleLabel.textColor = DefaultAppearance.shared.primaryLabelColor
            titleLabel.font = FontManager.shared.mediumFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.toolbarTitle)
            titleLabel.textAlignment = .center
            navigationItem.titleView = titleLabel
            
            // // Right button for Transaction History
            // let historyCustomButton = UIButton(type: .custom)
            // historyCustomButton.translatesAutoresizingMaskIntoConstraints = false
            // historyCustomButton.tintColor = DefaultAppearance.shared.primaryLabelColor
            
            // let historyImage = UIImage(named: "history", in: B24PaymentSdkHelper.frameworkBundle(), compatibleWith: nil)?
            //     .withTintColor(DefaultAppearance.shared.primaryLabelColor, renderingMode: .alwaysOriginal)
            
            // let historyImageView = UIImageView(image: historyImage)
            // historyImageView.contentMode = .scaleAspectFit
            // historyImageView.translatesAutoresizingMaskIntoConstraints = false
            // historyCustomButton.addSubview(historyImageView)
            
            // // Add constraints for the history icon
            // NSLayoutConstraint.activate([
            //     historyImageView.leadingAnchor.constraint(equalTo: historyCustomButton.leadingAnchor),
            //     historyImageView.trailingAnchor.constraint(equalTo: historyCustomButton.trailingAnchor),
            //     historyImageView.topAnchor.constraint(equalTo: historyCustomButton.topAnchor),
            //     historyImageView.bottomAnchor.constraint(equalTo: historyCustomButton.bottomAnchor),
            //     historyImageView.widthAnchor.constraint(equalToConstant: 30),
            //     historyImageView.heightAnchor.constraint(equalToConstant: 30)
            // ])
            
            // // Add action to the history button
            // historyCustomButton.addTarget(self, action: #selector(transactionButtonTapped), for: .touchUpInside)
            
            // // Create a UIBarButtonItem with the custom button
            // let historyButton = UIBarButtonItem(customView: historyCustomButton)
            // navigationItem.rightBarButtonItem = historyButton
        }
        
        @objc func transactionButtonTapped() {
            // Dismiss keyboard when opening transaction history
            view.endEditing(true)
            
            guard NetworkMonitor.shared.isConnected else {
                if !isWaitingForConnection {
                    isWaitingForConnection = true
                    
                    // Start monitoring on-demand since we found we are offline
                    setupNetworkMonitoring()
                    NetworkMonitor.shared.startMonitoring()
                    
                    B24PaymentSdkHelper.showNoInternetPopup(on: self) { [weak self] in
                        self?.isWaitingForConnection = false
                        B24PaymentSdkHelper.hideNoInternetPopup(from: self!, showSuccess: false)
                    }
                }
                return
            }
            
            showBottomSheet()
        }
        
        func showBottomSheet() {
            // Prevent multiple instances if already presented or transition in progress
            if transactionBottomSheet != nil { return }
            
            dismissBottomSheet()
            
            let storyboard = UIStoryboard(name: "InstantPaymentMethodView", bundle: B24PaymentSdkHelper.frameworkBundle())
            guard let bottomSheetVC = storyboard.instantiateViewController(withIdentifier: "TransactionsView") as? TransactionsView else { return }
        
            transactionBottomSheet = bottomSheetVC
            transactionBottomSheet?.accountId = self.walletId
            transactionBottomSheet?.delegate = self
        
            presentDraggableBottomSheet(transactionBottomSheet!)
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
                self?.transactionBottomSheet?.refreshInsets()
            }

            presentDraggableBottomSheet(transactionBottomSheet!)
            addDimBackground()
        }
        
        func dismissBottomSheet() {
            removeDimBackground()
            guard let bottomSheet = transactionBottomSheet,
                  bottomSheet.isViewLoaded,
                  bottomSheet.view.superview != nil else { return }
            
            UIView.animate(withDuration: 0.3, animations: {
                bottomSheet.view.frame.origin.y = self.view.bounds.height
            }, completion: { _ in
                bottomSheet.view.removeFromSuperview()
                bottomSheet.removeFromParent()
                self.transactionBottomSheet = nil
            })
        }
        
        private func presentDraggableBottomSheet(_ bottomSheetVC: TransactionsView) {
            guard let windowScene = UIApplication.shared.connectedScenes
                .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
                let window = windowScene.windows.first(where: { $0.isKeyWindow }) else {
                return
            }
//            addChild(bottomSheetVC)
            
            let screenHeight = view.bounds.height
            let largeHeight = BottomSheetDetent.large.height(for: screenHeight)
            
            bottomSheetVC.view.frame = CGRect(
                x: 0,
                y: screenHeight,
                width: view.bounds.width,
                height: largeHeight
            )
            
            bottomSheetVC.view.layer.cornerRadius = 16
            bottomSheetVC.view.layer.masksToBounds = true
            bottomSheetVC.view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
            
            window.addSubview(bottomSheetVC.view)
            bottomSheetVC.didMove(toParent: self)
            
            setupBottomSheetGestures(for: bottomSheetVC.view)
            
            currentDetentState = .large
            animateToDetent(.large, animated: true)
            
            transactionBottomSheet?.setBottomSheetState(collapsed: false)
        }

        // MARK: - Gesture Handling
        @objc private func handleBottomSheetPan(_ gesture: UIPanGestureRecognizer) {
            guard let bottomSheetView = gesture.view else { return }
            
            let screenHeight = view.bounds.height
            let translation = gesture.translation(in: view)
            
            let shouldHandle = shouldHandleBottomSheetGesture(gesture: gesture, translation: translation)
            
            switch gesture.state {
            case .began:
                let location = gesture.location(in: bottomSheetView)
                startedOnGrip = location.y <= 60
                
                isHandlingBottomSheetGesture = shouldHandle
                if isHandlingBottomSheetGesture {
                    initialBottomSheetY = bottomSheetView.frame.origin.y
                    lastHapticDetentState = currentDetentState
                }
                
            case .changed:
                if !isHandlingBottomSheetGesture { return }
                
                let newY = initialBottomSheetY + translation.y
                let minY = BottomSheetDetent.large.yPosition(for: screenHeight)
                
                // Allow dragging below large for dismissal
                // For pulling up (negative translation), only rubber-band if started on grip
                var constrainedY: CGFloat
                if newY < minY {
                    if startedOnGrip {
                        constrainedY = rubberBandClamp(value: newY, minValue: minY, maxValue: screenHeight)
                    } else {
                        // If started on list, lock at top to allow normal scrolling
                        constrainedY = minY
                    }
                } else {
                    constrainedY = newY
                }
                
                let newHeight = screenHeight - constrainedY
                
                CATransaction.begin()
                CATransaction.setDisableActions(true)
                bottomSheetView.frame = CGRect(x: 0, y: constrainedY, width: view.bounds.width, height: newHeight)
                CATransaction.commit()
                
                updateGripAppearance(for: constrainedY, screenHeight: screenHeight)
                checkAndTriggerHapticFeedback(for: constrainedY, screenHeight: screenHeight)
                
            case .ended:
                if isHandlingBottomSheetGesture {
                    DispatchQueue.main.async {
                        self.transactionBottomSheet?.refreshInsets()
                    }
                    let naturalVelocity = calculateNaturalVelocity(from: gesture)
                    handlePanGestureEnded(velocity: naturalVelocity, currentY: bottomSheetView.frame.origin.y)
                }
                isHandlingBottomSheetGesture = false
                lastHapticDetentState = nil
                
            case .cancelled, .failed:
                isHandlingBottomSheetGesture = false
                lastHapticDetentState = nil
                
            default:
                break
            }
        }
        
        private func checkAndTriggerHapticFeedback(for yPosition: CGFloat, screenHeight: CGFloat) {
            let largeY = BottomSheetDetent.large.yPosition(for: screenHeight)
            
            // Only trigger if we are very close to the snapping point
            if abs(yPosition - largeY) < 5 && lastHapticDetentState != .large {
                triggerHapticFeedback()
                lastHapticDetentState = .large
                transactionBottomSheet?.setBottomSheetState(collapsed: false)
            } else if yPosition > largeY + 50 && lastHapticDetentState == .large {
                lastHapticDetentState = nil
            }
        }
        
        private func triggerHapticFeedback() {
            let impactFeedback = UIImpactFeedbackGenerator(style: .soft)
            impactFeedback.impactOccurred(intensity: 0.6)
        }
        
        private func shouldHandleBottomSheetGesture(gesture: UIPanGestureRecognizer, translation: CGPoint) -> Bool {
            guard let bottomSheetView = transactionBottomSheet?.view,
                  let collectionView = transactionBottomSheet?.transactionCollectionView else {
                return true
            }
            
            let location = gesture.location(in: bottomSheetView)
            let gripAreaHeight: CGFloat = 60
            
            if location.y <= gripAreaHeight { return true }
            
            let contentOffset = collectionView.contentOffset.y
            
            // Coordinate with scroll view: allow dragging when at top of content
            if contentOffset <= 15 { return true }
            
            let contentHeight = collectionView.contentSize.height
            let frameHeight = collectionView.frame.height
            if translation.y < 0 && (contentOffset + frameHeight >= contentHeight - 15) {
                return true
            }
            
            return false
        }
        
        private func setupBottomSheetGestures(for bottomSheetView: UIView) {
            let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleBottomSheetPan(_:)))
            panGesture.delegate = self
            bottomSheetView.addGestureRecognizer(panGesture)
        }
        
        private func handlePanGestureEnded(velocity: CGFloat, currentY: CGFloat) {
            let screenHeight = view.bounds.height
            let largeY = BottomSheetDetent.large.yPosition(for: screenHeight)
            
            // Refined dismissal thresholds: 25% of screen height drag or high velocity flick
            let dismissThreshold = largeY + (screenHeight * 0.25)
            
            if currentY > dismissThreshold || velocity > 1200 {
                dismissBottomSheet()
            } else {
                currentDetentState = .large
                animateToDetent(.large, animated: true)
            }
        }
        
        private func animateToDetent(_ detent: BottomSheetDetent, animated: Bool = true) {
            animateToDetentWithVelocity(detent, initialVelocity: 0, animated: animated)
        }
        
        private func animateToDetentWithVelocity(_ detent: BottomSheetDetent, initialVelocity: CGFloat = 0, animated: Bool = true) {
            guard let bottomSheetView = transactionBottomSheet?.view else { return }
            
            let screenHeight = view.bounds.height
            let targetY = detent.yPosition(for: screenHeight)
            let targetHeight = detent.height(for: screenHeight)
            
            let animations = {
                bottomSheetView.frame = CGRect(x: 0, y: targetY, width: self.view.bounds.width, height: targetHeight)
                self.updateGripAppearance(for: targetY, screenHeight: screenHeight)
            }
            
            let completion: (Bool) -> Void = { _ in
                self.transactionBottomSheet?.refreshInsets()
                let isCollapsed = (detent == .medium)
                self.transactionBottomSheet?.setBottomSheetState(collapsed: isCollapsed)
            }
            
            if animated {
                let currentY = bottomSheetView.frame.origin.y
                let distance = abs(targetY - currentY)
                let baseVelocity: CGFloat = max(abs(initialVelocity), 300.0)
                let duration = min(max(distance / baseVelocity, 0.25), 0.8)
                
                let dampingRatio: CGFloat = detent == .large ? 0.82 : 0.88
                let springAnimator = UIViewPropertyAnimator(duration: TimeInterval(duration), dampingRatio: dampingRatio) {
                    animations()
                }
                springAnimator.addCompletion { _ in completion(true) }
                springAnimator.startAnimation()
            } else {
                animations()
                completion(true)
            }
        }
        
        private func rubberBandClamp(value: CGFloat, minValue: CGFloat, maxValue: CGFloat) -> CGFloat {
            if value < minValue {
                let diff = minValue - value
                let resistance = CGFloat(1.0 - pow(Double(min(diff, 100) / 100), 0.6))
                return minValue - (diff * resistance * 0.25)
            } else if value > maxValue {
                let diff = value - maxValue
                let resistance = CGFloat(1.0 - pow(Double(min(diff, 80) / 80), 0.8))
                return maxValue + (diff * resistance * 0.3)
            }
            return value
        }
        
        private func calculateNaturalVelocity(from gesture: UIPanGestureRecognizer) -> CGFloat {
            let velocity = gesture.velocity(in: view).y
            guard let bottomSheetView = transactionBottomSheet?.view else { return velocity }
            
            let screenHeight = view.bounds.height
            let currentY = bottomSheetView.frame.origin.y
            let minY = BottomSheetDetent.large.yPosition(for: screenHeight)
            let maxY = BottomSheetDetent.medium.yPosition(for: screenHeight)
            
            if currentY < minY {
                let dampingFactor = max(0.3, 1.0 - (minY - currentY) / 100.0 * 0.7)
                return velocity * dampingFactor
            } else if currentY > maxY {
                let dampingFactor = max(0.4, 1.0 - (currentY - maxY) / 150.0 * 0.6)
                return velocity * dampingFactor
            }
            return velocity
        }
        
        private func updateGripAppearance(for yPosition: CGFloat, screenHeight: CGFloat) {
            let mediumHeight = BottomSheetDetent.medium.height(for: screenHeight)
            let largeHeight = BottomSheetDetent.large.height(for: screenHeight)
            let currentHeight = screenHeight - yPosition
            
            let expansionFraction = (currentHeight - mediumHeight) / (largeHeight - mediumHeight)
            let clampedFraction = max(0.0, min(1.0, expansionFraction))
            
            transactionBottomSheet?.updateGripAppearance(progress: clampedFraction)
        }
        
        private func addBackgroundDimEffect(alpha: CGFloat) {
            if view.viewWithTag(999) == nil {
                let dimView = UIView()
                dimView.tag = 999
                dimView.backgroundColor = UIColor.black
                dimView.alpha = 0
                view.insertSubview(dimView, belowSubview: transactionBottomSheet!.view)
                
                // Add tap gesture to dismiss
                let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleBackgroundTap))
                dimView.addGestureRecognizer(tapGesture)
                
                dimView.translatesAutoresizingMaskIntoConstraints = false
                NSLayoutConstraint.activate([
                    dimView.topAnchor.constraint(equalTo: view.topAnchor),
                    dimView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                    dimView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                    dimView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
                ])
            }
            view.viewWithTag(999)?.alpha = alpha
        }

        // Back button action
        @objc func backButtonTapped() {
            //navigationController?.popViewController(animated: true)
            if let navigationController = navigationController {
                if navigationController.viewControllers.count > 1 {
                    // Pop if not the root view controller
                    navigationController.popViewController(animated: true)
                } else {
                    // Dismiss if this is the root view controller
                    dismiss(animated: true, completion: nil)
                }
            } else {
                // Dismiss if not in a navigation controller
                dismiss(animated: true, completion: nil)
            }
        }
    
    

    func updateAmountListForCurrency() {
        switch currency.uppercased() {
        case "USD":
            currentAmountList = usdAmountList
        case "KHR":
            currentAmountList = khrAmountList
        default:
            currentAmountList = usdAmountList // Default to USD if unknown currency
        }
    }

    
//    func setUpColelctionView(){
//        
//        // Register the custom cell
//        let nibName = UINib(nibName: "AmountViewCell", bundle: B24PaymentSdkHelper.frameworkBundle())
//        self.amountCollectionView.register(nibName, forCellWithReuseIdentifier: "AmountViewCell")
//                
//        self.amountCollectionView.delegate = self
//        self.amountCollectionView.dataSource = self
//                
//        self.amountCollectionView.reloadData()
//        // Select the default item
//        amountCollectionView.selectItem(at: defaultSelectedIndex, animated: false, scrollPosition: .centeredVertically)
//        // Set the default item's value to the inputAmount text field
//        topUpAmount = amountList[defaultSelectedIndex.row]
//        inputAmount.text = topUpAmount
//        
//    }

    // Update setUpCollectionView to use currentAmountList
    func setUpColelctionView() {
        let nibName = UINib(nibName: "AmountViewCell", bundle: B24PaymentSdkHelper.frameworkBundle())
        self.amountCollectionView.register(nibName, forCellWithReuseIdentifier: "AmountViewCell")

        self.amountCollectionView.delegate = self
        self.amountCollectionView.dataSource = self

        self.amountCollectionView.isScrollEnabled = false
        self.amountCollectionView.reloadData()

        amountCollectionView.selectItem(at: defaultSelectedIndex, animated: false, scrollPosition: .centeredVertically)
        topUpAmount = currentAmountList[defaultSelectedIndex.row]
        inputAmount.text = topUpAmount
    }

    
    func setUpTopUI() {
        contenContainer.backgroundColor = .clear
        contenContainer.addCardShadow(cornerRadius: 16)
        contenContainer.roundCorners(cornerRadius: 16)
        line.isHidden = true

        // Gradient background layer (only added once)
        if contenContainer.viewWithTag(1003) == nil {
            let gradientView = UIView()
            gradientView.tag = 1003
            gradientView.translatesAutoresizingMaskIntoConstraints = false
            gradientView.layer.cornerRadius = 16
            gradientView.clipsToBounds = true
            contenContainer.insertSubview(gradientView, at: 0)
            NSLayoutConstraint.activate([
                gradientView.topAnchor.constraint(equalTo: contenContainer.topAnchor),
                gradientView.leadingAnchor.constraint(equalTo: contenContainer.leadingAnchor),
                gradientView.trailingAnchor.constraint(equalTo: contenContainer.trailingAnchor),
                gradientView.bottomAnchor.constraint(equalTo: contenContainer.bottomAnchor)
            ])
            let gradient = CAGradientLayer()
            gradient.colors = [
                DefaultAppearance.shared.walletCardColor.blended(with: .white, ratio: 0.08).cgColor,
                DefaultAppearance.shared.walletCardColor.cgColor,
                DefaultAppearance.shared.walletCardColor.blended(with: .black, ratio: 0.22).cgColor
            ]
            gradient.locations = [0.0, 0.6, 1.0]
            gradient.startPoint = CGPoint(x: 0.1, y: 0.0)
            gradient.endPoint = CGPoint(x: 0.9, y: 1.0)
            gradientView.layer.addSublayer(gradient)
            cardGradientLayer = gradient

            // Large hexagon — top-right, 8% sky blue opacity
            let large = CAShapeLayer()
            large.fillColor = UIColor(hex: "#54A6DB").withAlphaComponent(0.08).cgColor
            large.strokeColor = UIColor.clear.cgColor
            gradientView.layer.addSublayer(large)
            hexagonLarge = large

            // Small hexagon — bottom-right area, 5% sky blue opacity
            let small = CAShapeLayer()
            small.fillColor = UIColor(hex: "#54A6DB").withAlphaComponent(0.05).cgColor
            small.strokeColor = UIColor.clear.cgColor
            gradientView.layer.addSublayer(small)
            hexagonSmall = small
        }

        cardGradientLayer?.colors = [
            DefaultAppearance.shared.walletCardColor.blended(with: .white, ratio: 0.08).cgColor,
            DefaultAppearance.shared.walletCardColor.cgColor,
            DefaultAppearance.shared.walletCardColor.blended(with: .black, ratio: 0.22).cgColor
        ]

        // Wallet icon (top-right, only added once)
        if contenContainer.viewWithTag(1001) == nil {
            let logoBackgroundView = UIView()
            logoBackgroundView.tag = 1001
            logoBackgroundView.backgroundColor = DefaultAppearance.shared.onPrimaryColor.withAlphaComponent(0.15)
            logoBackgroundView.layer.cornerRadius = 8
            logoBackgroundView.layer.borderColor = DefaultAppearance.shared.onPrimaryColor.withAlphaComponent(0.2).cgColor
            logoBackgroundView.layer.borderWidth = 1
            logoBackgroundView.translatesAutoresizingMaskIntoConstraints = false
            contenContainer.addSubview(logoBackgroundView)

            let logoImageView = UIImageView()
            logoImageView.image = UIImage(named: "wallet", in: B24PaymentSdkHelper.frameworkBundle(), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
            logoImageView.tintColor = DefaultAppearance.shared.onPrimaryColor.withAlphaComponent(0.8)
            logoImageView.contentMode = .scaleAspectFit
            logoImageView.translatesAutoresizingMaskIntoConstraints = false
            logoBackgroundView.addSubview(logoImageView)

            NSLayoutConstraint.activate([
                logoBackgroundView.topAnchor.constraint(equalTo: contenContainer.topAnchor, constant: 20),
                logoBackgroundView.trailingAnchor.constraint(equalTo: contenContainer.trailingAnchor, constant: -20),
                logoBackgroundView.widthAnchor.constraint(equalToConstant: 40),
                logoBackgroundView.heightAnchor.constraint(equalToConstant: 40),

                logoImageView.centerXAnchor.constraint(equalTo: logoBackgroundView.centerXAnchor),
                logoImageView.centerYAnchor.constraint(equalTo: logoBackgroundView.centerYAnchor),
                logoImageView.widthAnchor.constraint(equalToConstant: 20),
                logoImageView.heightAnchor.constraint(equalToConstant: 20)
            ])
        }

        // Wallet name — bold 17pt
        TitleLabel.text = walletName
        TitleLabel.textColor = DefaultAppearance.shared.onPrimaryColor
        TitleLabel.font = FontManager.shared.boldFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.toolbarTitle)
        TitleLabel.numberOfLines = 1
        TitleLabel.lineBreakMode = .byTruncatingTail
        TitleLabel.adjustsFontSizeToFitWidth = false
        TitleLabel.setContentCompressionResistancePriority(.required, for: .vertical)
        TitleLabel.setContentHuggingPriority(.required, for: .vertical)

        // Wallet ID — 12pt, 50% white
        walletNo.text = wallet
        walletNo.textColor = DefaultAppearance.shared.onPrimaryColor.withAlphaComponent(0.5)
        walletNo.font = FontManager.shared.regularFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.tranTypeText)
        walletNo.numberOfLines = 0
        walletNo.lineBreakMode = .byWordWrapping
        walletNo.adjustsFontSizeToFitWidth = false
        walletNo.setContentCompressionResistancePriority(.required, for: .vertical)
        walletNo.setContentHuggingPriority(.required, for: .vertical)

        // Balance label — uppercase, letter-spaced, 11pt, 60% white
        let balanceText = B24PaymentSdkHelper.localized(AddWalletLocalizedKeys.balance.rawValue).uppercased()
        balanceLabel.attributedText = NSAttributedString(string: balanceText, attributes: [
            .kern: 0.6,
            .font: FontManager.shared.mediumFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.walletBalanceLabel),
            .foregroundColor: DefaultAppearance.shared.onPrimaryColor.withAlphaComponent(0.6)
        ])
        balanceLabel.numberOfLines = 0
        balanceLabel.lineBreakMode = .byWordWrapping
        balanceLabel.adjustsFontSizeToFitWidth = false
        balanceLabel.setContentCompressionResistancePriority(.required, for: .vertical)
        balanceLabel.setContentHuggingPriority(.required, for: .vertical)

        // Amount + currency inline
        let cleanBalance = balance
            .replacingOccurrences(of: currency, with: "", options: .caseInsensitive)
            .trimmingCharacters(in: .whitespaces)
        let currencyText = currency.trimmingCharacters(in: .whitespacesAndNewlines)
        let amountAttr = NSMutableAttributedString(string: cleanBalance, attributes: [
            .font: FontManager.shared.boldFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.walletBalance),
            .foregroundColor: DefaultAppearance.shared.onPrimaryColor
        ])
        amountAttr.append(NSAttributedString(string: "  \(currencyText)", attributes: [
            .font: FontManager.shared.regularFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.cardSubTitle),
            .foregroundColor: DefaultAppearance.shared.onPrimaryColor
        ]))
        amountLabel.attributedText = amountAttr
        let isKhmerHeader = (language ?? "km").lowercased() == "km"
        amountLabel.numberOfLines = 0
        amountLabel.lineBreakMode = .byWordWrapping
        amountLabel.adjustsFontSizeToFitWidth = !isKhmerHeader
        amountLabel.minimumScaleFactor = 0.6
        amountLabel.setContentCompressionResistancePriority(.required, for: .vertical)
        amountLabel.setContentHuggingPriority(.required, for: .vertical)

        // Remove old currency pill — currency is now inline in amountLabel
        currencyLabel.isHidden = true
        contenContainer.viewWithTag(1002)?.removeFromSuperview()

        // Layout
        [TitleLabel, walletNo, balanceLabel, amountLabel].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            $0.removeConstraints($0.constraints)
        }
        contenContainer.constraints.forEach { constraint in
            let involvesOurLabels = [TitleLabel, walletNo, balanceLabel, amountLabel].contains { label in
                (constraint.firstItem as? UILabel) === label || (constraint.secondItem as? UILabel) === label
            }
            if involvesOurLabels { constraint.isActive = false }
        }

        // Powered by Bill24 label (bottom-right of card, only added once)
        contenContainer.viewWithTag(1004)?.removeFromSuperview()
        let poweredByLabel = UILabel()
        poweredByLabel.tag = 1004
        poweredByLabel.translatesAutoresizingMaskIntoConstraints = false
        poweredByLabel.textAlignment = .right
        let poweredAttr = NSMutableAttributedString(
            string: "Powered by ",
            attributes: [
                .font: UIFont.italicSystemFont(ofSize: FixFontSize.poweredByText),
                .foregroundColor: DefaultAppearance.shared.onPrimaryColor.withAlphaComponent(0.4)
            ]
        )
        poweredAttr.append(NSAttributedString(
            string: "Bill24",
            attributes: [
                .font: FontManager.shared.boldFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.walletBalanceLabel),
                .foregroundColor: DefaultAppearance.shared.onPrimaryColor.withAlphaComponent(0.7)
            ]
        ))
        poweredByLabel.attributedText = poweredAttr
        poweredByLabel.isUserInteractionEnabled = true
        poweredByLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(navigateToBill24Url)))
        contenContainer.addSubview(poweredByLabel)

        NSLayoutConstraint.activate([
            TitleLabel.topAnchor.constraint(equalTo: contenContainer.topAnchor, constant: 20),
            TitleLabel.leadingAnchor.constraint(equalTo: contenContainer.leadingAnchor, constant: 20),
            TitleLabel.trailingAnchor.constraint(lessThanOrEqualTo: contenContainer.viewWithTag(1001)?.leadingAnchor ?? contenContainer.trailingAnchor, constant: -12),

            walletNo.topAnchor.constraint(equalTo: TitleLabel.bottomAnchor, constant: 2),
            walletNo.leadingAnchor.constraint(equalTo: contenContainer.leadingAnchor, constant: 20),

            balanceLabel.topAnchor.constraint(equalTo: walletNo.bottomAnchor, constant: 16),
            balanceLabel.leadingAnchor.constraint(equalTo: contenContainer.leadingAnchor, constant: 20),

            amountLabel.topAnchor.constraint(equalTo: balanceLabel.bottomAnchor, constant: 4),
            amountLabel.leadingAnchor.constraint(equalTo: contenContainer.leadingAnchor, constant: 20),
            amountLabel.trailingAnchor.constraint(lessThanOrEqualTo: contenContainer.trailingAnchor, constant: -20),

            poweredByLabel.topAnchor.constraint(equalTo: amountLabel.bottomAnchor, constant: 14),
            poweredByLabel.trailingAnchor.constraint(equalTo: contenContainer.trailingAnchor, constant: -20),
            poweredByLabel.bottomAnchor.constraint(equalTo: contenContainer.bottomAnchor, constant: -20)
        ])
    }
    
    func setUpBottomUI() {
        bottomView.backgroundColor = DefaultAppearance.shared.screenBgColor
        chooseAmountLabel.text = B24PaymentSdkHelper.localized(AddWalletLocalizedKeys.choose_amount.rawValue)
        chooseAmountLabel.font = FontManager.shared.mediumFont(forLanguage: language ?? "km",fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.contentText)
        chooseAmountLabel.textColor = DefaultAppearance.shared.primaryLabelColor
                
        // Adjust spacing for lineChooseAmount
        for constraint in bottomView.constraints {
            if (constraint.firstItem as? UIView) == lineChooseAmount && constraint.firstAttribute == .top {
                constraint.constant = 8 // Reduce spacing after label
            }
        }

        lineChooseAmount.backgroundColor = DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.1)

        // Configure input amount text field
        inputAmount.backgroundColor = DefaultAppearance.shared.cardColor
        inputAmount.layer.cornerRadius = 12
        inputAmount.layer.borderWidth = 1.5
        inputAmount.layer.borderColor = DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.15).cgColor
        inputAmount.layer.masksToBounds = true
        inputAmount.keyboardType = .decimalPad
        inputAmount.font = B24PaymentSdkHelper.setFont(named: FixFontFamily.fontEnglishMedium, ofSize: FixFontSize.toolbarTitle)
        inputAmount.textColor = DefaultAppearance.shared.primaryLabelColor
        self.addPadding(to: inputAmount)
        
        // Adjust input field spacing
        for constraint in bottomView.constraints {
            if (constraint.firstItem as? UITextField) == inputAmount && constraint.firstAttribute == .top {
                constraint.constant = 12 // Reduce spacing after line
            }
        }

        amountCollectionView.backgroundColor = DefaultAppearance.shared.screenBgColor
        
        // Adjust collection view spacing
        for constraint in bottomView.constraints {
            if (constraint.firstItem as? UICollectionView) == amountCollectionView && constraint.firstAttribute == .top {
                constraint.constant = 12 // Reduce spacing after input
            }
        }

        let buttonAttribute = NSAttributedString(
            string: B24PaymentSdkHelper.localized(TopupLocalizedKeys.continueKey.rawValue),
            attributes: [
                .font: FontManager.shared.regularFont(forLanguage: self.language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish,size: FixFontSize.buttonText),
                .foregroundColor: DefaultAppearance.shared.onPrimaryColor
            ]
        )
        self.buttonOk.setAttributedTitle(buttonAttribute, for: .normal)
        self.buttonOk.tintColor = DefaultAppearance.shared.primaryColor
        self.buttonOk.layer.cornerRadius = 12

        setupRecentTransactionUI()
    }
    
    private func setupRecentTransactionUI() {
        recentTransactionContainer.translatesAutoresizingMaskIntoConstraints = false
        recentTransactionContainer.isHidden = true 
        
        // Header
        recentTransactionHeader.translatesAutoresizingMaskIntoConstraints = false
        recentTransactionContainer.addSubview(recentTransactionHeader)
        
        recentTransactionLabel.text = B24PaymentSdkHelper.localized(TransactionDetailLocalizedKeys.tran_recent.rawValue)
        recentTransactionLabel.font = FontManager.shared.mediumFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.contentText)
        recentTransactionLabel.textColor = DefaultAppearance.shared.primaryLabelColor
        recentTransactionLabel.translatesAutoresizingMaskIntoConstraints = false
        recentTransactionHeader.addSubview(recentTransactionLabel)
        
        let viewAllTitle = NSAttributedString(
            string: B24PaymentSdkHelper.localized(AddWalletLocalizedKeys.view_all.rawValue),
            attributes: [
                .font: FontManager.shared.mediumFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.contentText),
                .foregroundColor: DefaultAppearance.shared.primaryColor
            ]
        )
        viewAllButton.setAttributedTitle(viewAllTitle, for: .normal)
        viewAllButton.addTarget(self, action: #selector(transactionButtonTapped), for: .touchUpInside)
        viewAllButton.translatesAutoresizingMaskIntoConstraints = false
        recentTransactionHeader.addSubview(viewAllButton)
        
        // Loader
        recentTransactionLoader.translatesAutoresizingMaskIntoConstraints = false
        recentTransactionLoader.hidesWhenStopped = true
        recentTransactionLoader.color = DefaultAppearance.shared.primaryColor
        recentTransactionContainer.addSubview(recentTransactionLoader)
        recentTransactionContainer.bringSubviewToFront(recentTransactionLoader)
        
        // StackView for rows
        recentTransactionPreview.axis = .vertical
        recentTransactionPreview.spacing = 10
        recentTransactionPreview.alignment = .fill
        recentTransactionPreview.distribution = .fill
        recentTransactionPreview.translatesAutoresizingMaskIntoConstraints = false
        recentTransactionContainer.addSubview(recentTransactionPreview)
        
        // Constraints
        NSLayoutConstraint.activate([
            recentTransactionHeader.topAnchor.constraint(equalTo: recentTransactionContainer.topAnchor),
            recentTransactionHeader.leadingAnchor.constraint(equalTo: recentTransactionContainer.leadingAnchor),
            recentTransactionHeader.trailingAnchor.constraint(equalTo: recentTransactionContainer.trailingAnchor),
            recentTransactionHeader.heightAnchor.constraint(equalToConstant: 30),
            
            recentTransactionLabel.leadingAnchor.constraint(equalTo: recentTransactionHeader.leadingAnchor),
            recentTransactionLabel.centerYAnchor.constraint(equalTo: recentTransactionHeader.centerYAnchor),
            
            viewAllButton.trailingAnchor.constraint(equalTo: recentTransactionHeader.trailingAnchor),
            viewAllButton.centerYAnchor.constraint(equalTo: recentTransactionHeader.centerYAnchor),
            
            recentTransactionPreview.topAnchor.constraint(equalTo: recentTransactionHeader.bottomAnchor, constant: 10),
            recentTransactionPreview.leadingAnchor.constraint(equalTo: recentTransactionContainer.leadingAnchor),
            recentTransactionPreview.trailingAnchor.constraint(equalTo: recentTransactionContainer.trailingAnchor),
            recentTransactionPreview.bottomAnchor.constraint(equalTo: recentTransactionContainer.bottomAnchor),
            
            recentTransactionLoader.centerXAnchor.constraint(equalTo: recentTransactionPreview.centerXAnchor),
            recentTransactionLoader.centerYAnchor.constraint(equalTo: recentTransactionPreview.centerYAnchor)
        ])
        
        loaderHeightConstraint = recentTransactionPreview.heightAnchor.constraint(equalToConstant: 120)
    }
    
    // MARK: - Fetch Balance
    private func fetchBalance() {
        guard !walletId.isEmpty else { return }
        guard NetworkMonitor.shared.isConnected else { return }

        AF.request(WalletRouter.instantPaymentMethodDetail(id: walletId))
            .validate().responseData { [weak self] response in
                guard let self = self else { return }
                self.refreshControl.endRefreshing()
                switch response.result {
                case .success(let data):
                    do {
                        let decodeData = try JSONDecoder().decode(ApiResponse<DataAccountDetail>.self, from: data)
                        if decodeData.code == StatusCode.succcess.rawValue {
                            self.balance = decodeData.data.amountDisplay
                            self.currency = decodeData.data.currency
                            SharedPreferenceManager.set(value: self.balance, forKey: SharePrefKey.balance.rawValue)
                            DispatchQueue.main.async {
                                self.updateBalanceDisplay()
                            }
                        }
                    } catch {
                        print("Balance Decode Error: \(error)")
                    }
                case .failure:
                    break
                }
            }
    }

    private func updateBalanceDisplay() {
        let cleanBalance = balance
            .replacingOccurrences(of: currency, with: "", options: .caseInsensitive)
            .trimmingCharacters(in: .whitespaces)
        let currencyText = currency.trimmingCharacters(in: .whitespacesAndNewlines)
        let amountAttr = NSMutableAttributedString(string: cleanBalance, attributes: [
            .font: FontManager.shared.boldFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.walletBalance),
            .foregroundColor: DefaultAppearance.shared.onPrimaryColor
        ])
        amountAttr.append(NSAttributedString(string: "  \(currencyText)", attributes: [
            .font: FontManager.shared.regularFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.cardSubTitle),
            .foregroundColor: DefaultAppearance.shared.onPrimaryColor
        ]))
        amountLabel.attributedText = amountAttr
    }

    private func fetchRecentTransaction() {
        guard !walletId.isEmpty else { return }
        guard !isFetchingTransactions else { return }

        isFetchingTransactions = true

        // Clear previous state (rows or empty messages) before starting fetch
        recentTransactionPreview.arrangedSubviews.forEach { $0.removeFromSuperview() }

        guard NetworkMonitor.shared.isConnected else {
            isFetchingTransactions = false
            refreshControl.endRefreshing()
            if !isWaitingForConnection {
                isWaitingForConnection = true
                setupNetworkMonitoring()
                NetworkMonitor.shared.startMonitoring()
            }
            // Show offline message instead of "No History"
            showRecentTransactionEmptyState(message: B24PaymentSdkHelper.localized(SnackBarLocalizedKeys.error_connect_server.rawValue))
            return
        }

        let url = APIManager.merchantApiUrl().appendingPathComponent("instantpaymentsdk/payment_method/transactions")
        let parameters: [String: Any] = [
            "id": walletId,
            "pagination": [
                "current_page": 1,
                "page_size": 5
            ]
        ]
        print("TopUpView recent transactions request -> url: \(url.absoluteString), payload: \(parameters)")
        
        recentTransactionContainer.isHidden = false
        loaderHeightConstraint?.isActive = true
        DispatchQueue.main.async {
            self.recentTransactionLoader.startAnimating()
        }
        
        AF.request(
            url,
            method: .post,
            parameters: parameters,
            encoding: JSONEncoding.default,
            headers: APIManager.initHeader()
        )
        .validate()
        .responseDecodable(of: DWalletTransactionResponseModel.self) { [weak self] response in
            guard let self = self else { return }
            self.isFetchingTransactions = false
            self.refreshControl.endRefreshing()
            self.loaderHeightConstraint?.isActive = false
            DispatchQueue.main.async {
                self.recentTransactionLoader.stopAnimating()
            }

            switch response.result {
            case .success(let responseModel):
                if responseModel.code == StatusCode.succcess.rawValue {
                    let transactions = responseModel.data.transactions
                    debugLogRecentTransactions(transactions, context: "TopUpView recent transactions response")
                    self.recentTransactions = transactions
                    if !transactions.isEmpty {
                        self.updateRecentTransactionUI(with: transactions)
                    } else {
                        self.recentTransactionContainer.isHidden = true
                    }
                    self.evaluatePolling(transactions: transactions)
                } else {
                    let message = (self.language?.lowercased() == "en") ? responseModel.message : responseModel.messageKh
                    self.showRecentTransactionEmptyState(message: message)
                }
            case .failure(let error):
                self.isFetchingTransactions = false
                if error.isSessionTaskError {
                    if !self.isWaitingForConnection {
                        self.isWaitingForConnection = true
                        self.setupNetworkMonitoring()
                        NetworkMonitor.shared.startMonitoring()
                    }
                    self.showRecentTransactionEmptyState(message: B24PaymentSdkHelper.localized(SnackBarLocalizedKeys.error_connect_server.rawValue))
                } else {
                    self.showRecentTransactionEmptyState()
                }
            }
        }
    }
    
    private func showRecentTransactionEmptyState(message: String? = nil) {
        recentTransactionContainer.isHidden = true
    }

    // MARK: - Transaction Polling Control

    private func evaluatePolling(transactions: [DWalletTransaction]) {
        let processingTopUps = transactions.filter {
            $0.tranType == TransactionType.walletTopup.rawValue && $0.status == "processing"
        }

        if !processingTopUps.isEmpty {
            print("[TopUpView Polling] Found \(processingTopUps.count) processing top-up(s): \(processingTopUps.map { $0.tranID })")
            startPollingIfNeeded()
        } else {
            if isPolling {
                print("[TopUpView Polling] No more processing top-ups — stopping polling & fetching balance")
                stopPolling()
                silentFetchBalance()
            }
        }
    }

    private func startPollingIfNeeded() {
        guard !isPolling else { return }
        guard pollingRetryCount < maxPollingRetries else {
            print("[TopUpView Polling] Max retries (\(maxPollingRetries)) reached — stopping")
            stopPolling()
            return
        }
        isPolling = true
        print("[TopUpView Polling] START polling (interval: \(pollingInterval)s)")
        pollingTimer = Timer.scheduledTimer(
            timeInterval: pollingInterval,
            target: self,
            selector: #selector(pollingTick),
            userInfo: nil,
            repeats: true
        )
    }

    @objc private func pollingTick() {
        pollingRetryCount += 1
        print("[TopUpView Polling] Tick #\(pollingRetryCount)/\(maxPollingRetries)")
        if pollingRetryCount >= maxPollingRetries {
            print("[TopUpView Polling] Max retries reached — stopping")
            stopPolling()
            return
        }
        guard !isFetchingTransactions else {
            print("[TopUpView Polling] Skipping tick — fetch still in-flight")
            return
        }
        silentFetchRecentTransaction()
    }

    private func stopPolling() {
        let wasPolling = isPolling
        pollingTimer?.invalidate()
        pollingTimer = nil
        isPolling = false
        pollingRetryCount = 0
        if wasPolling {
            print("[TopUpView Polling] STOPPED")
        }
    }

    // MARK: - Silent Fetches (polling only — no loaders)

    private func silentFetchRecentTransaction() {
        guard !isFetchingTransactions else { return }
        guard NetworkMonitor.shared.isConnected else {
            print("[TopUpView Polling] Silent fetch skipped — no network")
            return
        }

        isFetchingTransactions = true
        print("[TopUpView Polling] Silent fetching transactions...")

        let url = APIManager.merchantApiUrl()
            .appendingPathComponent("instantpaymentsdk/payment_method/transactions")
        let parameters: [String: Any] = [
            "id": walletId,
            "pagination": ["current_page": 1, "page_size": 5]
        ]

        AF.request(url, method: .post, parameters: parameters,
                   encoding: JSONEncoding.default, headers: APIManager.initHeader())
            .validate()
            .responseDecodable(of: DWalletTransactionResponseModel.self) { [weak self] response in
                guard let self = self else { return }
                self.isFetchingTransactions = false

                if case .success(let responseModel) = response.result,
                   responseModel.code == StatusCode.succcess.rawValue {
                    let transactions = responseModel.data.transactions
                    print("[TopUpView Polling] Silent fetch got \(transactions.count) transactions")
                    self.recentTransactions = transactions
                    if !transactions.isEmpty {
                        self.updateRecentTransactionUI(with: transactions)
                    }
                    self.evaluatePolling(transactions: transactions)
                } else {
                    print("[TopUpView Polling] Silent fetch failed — will retry next tick")
                }
            }
    }

    private func silentFetchBalance() {
        guard !isFetchingBalance else { return }
        guard NetworkMonitor.shared.isConnected else { return }

        isFetchingBalance = true
        print("[TopUpView Polling] Silent fetching balance...")

        AF.request(WalletRouter.instantPaymentMethodDetail(id: walletId))
            .validate().responseData { [weak self] response in
                guard let self = self else { return }
                self.isFetchingBalance = false

                if case .success(let data) = response.result,
                   let decoded = try? JSONDecoder().decode(
                       ApiResponse<DataAccountDetail>.self, from: data),
                   decoded.code == StatusCode.succcess.rawValue {
                    self.balance = decoded.data.amountDisplay
                    self.currency = decoded.data.currency
                    SharedPreferenceManager.set(
                        value: self.balance, forKey: SharePrefKey.balance.rawValue)
                    print("[TopUpView Polling] Balance updated: \(decoded.data.amountDisplay)")
                    DispatchQueue.main.async {
                        self.updateBalanceDisplay()
                    }
                } else {
                    print("[TopUpView Polling] Silent balance fetch failed")
                }
            }
    }

    private func updateRecentTransactionUI(with transactions: [DWalletTransaction]) {
        // Clear previous entries
        recentTransactionPreview.arrangedSubviews.forEach { $0.removeFromSuperview() }
        
        let maxCount = min(transactions.count, 5)
        
        for i in 0..<maxCount {
            let transaction = transactions[i]
            let row = createTransactionRow(from: transaction)
            row.tag = i
            row.isUserInteractionEnabled = true
            let tap = UITapGestureRecognizer(target: self, action: #selector(recentTransactionTapped(_:)))
            row.addGestureRecognizer(tap)
            
            recentTransactionPreview.addArrangedSubview(row)
            
            NSLayoutConstraint.activate([
                row.heightAnchor.constraint(equalToConstant: 70)
            ])
        }
        
        recentTransactionContainer.isHidden = false
    }

    @objc private func recentTransactionTapped(_ sender: UITapGestureRecognizer) {
        // Dismiss keyboard
        view.endEditing(true)
        
        guard NetworkMonitor.shared.isConnected else {
            if !isWaitingForConnection {
                isWaitingForConnection = true
                
                // Start monitoring on-demand since we found we are offline
                setupNetworkMonitoring()
                NetworkMonitor.shared.startMonitoring()
                
                B24PaymentSdkHelper.showNoInternetPopup(on: self) { [weak self] in
                    guard let self = self else { return }
                    self.isWaitingForConnection = false
                    B24PaymentSdkHelper.hideNoInternetPopup(from: self, showSuccess: false)
                }
            }
            return
        }
        
        guard let view = sender.view, view.tag < recentTransactions.count else { return }
        let selectedTransaction = recentTransactions[view.tag]
        
        let storyboard = UIStoryboard(name: "InstantPaymentMethodView", bundle: B24PaymentSdkHelper.frameworkBundle())
        guard let transactionDetailVC = storyboard.instantiateViewController(withIdentifier: "TransactionDetailView") as? TransactionDetailView else { return }

        transactionDetailVC.tranID = selectedTransaction.tranID
        
        // Store reference to forward connection changes
        self.transactionDetailView = transactionDetailVC
        
        transactionDetailVC.modalPresentationStyle = .overFullScreen
        self.present(transactionDetailVC, animated: false) {
            // Send initial connection state after view is presented
            self.transactionDetailView?.handleConnectionChange(isConnected: NetworkMonitor.shared.isConnected)
        }
    }

    private func createTransactionRow(from transaction: DWalletTransaction) -> UIView {
        let row = UIView()
        row.translatesAutoresizingMaskIntoConstraints = false
        row.backgroundColor = DefaultAppearance.shared.cardColor
        row.layer.cornerRadius = 12
        
        let logoBg = UIView()
        let isTopup = transaction.tranType == TransactionType.walletTopup.rawValue
        logoBg.backgroundColor = isTopup ? DefaultAppearance.shared.successColor.withAlphaComponent(0.1) : DefaultAppearance.shared.dangerColor.withAlphaComponent(0.1)
        logoBg.layer.cornerRadius = 20
        logoBg.clipsToBounds = true
        logoBg.translatesAutoresizingMaskIntoConstraints = false
        row.addSubview(logoBg)
        
        let logo = UIImageView()
        logo.translatesAutoresizingMaskIntoConstraints = false
        logoBg.addSubview(logo)
        
        // Helper to update logo constraints (matches setLogoFill in TransactionViewCell)
        var logoConstraints: [NSLayoutConstraint] = []
        func setLogoFill(_ fill: Bool) {
            NSLayoutConstraint.deactivate(logoConstraints)
            logoConstraints.removeAll()
            
            if fill {
                logoConstraints = [
                    logo.topAnchor.constraint(equalTo: logoBg.topAnchor),
                    logo.bottomAnchor.constraint(equalTo: logoBg.bottomAnchor),
                    logo.leadingAnchor.constraint(equalTo: logoBg.leadingAnchor),
                    logo.trailingAnchor.constraint(equalTo: logoBg.trailingAnchor)
                ]
                logo.contentMode = .scaleAspectFill
            } else {
                logoConstraints = [
                    logo.centerXAnchor.constraint(equalTo: logoBg.centerXAnchor),
                    logo.centerYAnchor.constraint(equalTo: logoBg.centerYAnchor),
                    logo.widthAnchor.constraint(equalTo: logoBg.widthAnchor, multiplier: 0.4),
                    logo.heightAnchor.constraint(equalTo: logoBg.heightAnchor, multiplier: 0.4)
                ]
                logo.contentMode = .scaleAspectFit
            }
            NSLayoutConstraint.activate(logoConstraints)
        }
        
        let resolvedLanguage = language ?? "km"
        let isKhmer = resolvedLanguage.lowercased() == "km"

        let titleLabel = UILabel()
        titleLabel.font = isKhmer
            ? FontManager.shared.regularFont(forLanguage: resolvedLanguage, fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.tranText)
            : FontManager.shared.mediumFont(forLanguage: resolvedLanguage, fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.tranText)
        titleLabel.textColor = DefaultAppearance.shared.secondaryLabelColor
        titleLabel.numberOfLines = 0
        titleLabel.lineBreakMode = .byWordWrapping
        titleLabel.adjustsFontSizeToFitWidth = false
        titleLabel.setContentCompressionResistancePriority(.required, for: .vertical)
        titleLabel.setContentHuggingPriority(.required, for: .vertical)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false

        let detailLabel = UILabel()
        detailLabel.font = FontManager.shared.regularFont(
            forLanguage: resolvedLanguage,
            fontFromconfig: DefaultAppearance.shared.fontEnglish,
            size: FixFontSize.tranTypeText
        )
        detailLabel.textColor = DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.4)
        detailLabel.numberOfLines = 0
        detailLabel.lineBreakMode = .byWordWrapping
        detailLabel.adjustsFontSizeToFitWidth = false
        detailLabel.setContentCompressionResistancePriority(.required, for: .vertical)
        detailLabel.setContentHuggingPriority(.required, for: .vertical)
        detailLabel.translatesAutoresizingMaskIntoConstraints = false
        
        // Use UIStackView for labels are centered vertically 
        // as a group. This handles different font metrics and baselines.
        let labelStack = UIStackView(arrangedSubviews: [titleLabel, detailLabel])
        labelStack.axis = .vertical
        labelStack.spacing = 2
        labelStack.alignment = .leading
        labelStack.translatesAutoresizingMaskIntoConstraints = false
        row.addSubview(labelStack)
        
        let amountLabel = UILabel()
        amountLabel.font = FontManager.shared.mediumFont(forLanguage: "en", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.buttonText)
        amountLabel.textAlignment = .right
        amountLabel.translatesAutoresizingMaskIntoConstraints = false
        row.addSubview(amountLabel)

        // Set data
        if isTopup {
            let value = (transaction.paidFrom?.isEmpty == false) ? transaction.paidFrom! : "N/A"
            titleLabel.text = value
            
            let descEn = transaction.descriptionEn.trimmingCharacters(in: .whitespacesAndNewlines)
            let descKm = transaction.descriptionKm.trimmingCharacters(in: .whitespacesAndNewlines)
            if language?.lowercased() == "en" {
                detailLabel.text = descEn.isEmpty ? B24PaymentSdkHelper.localized(TopupLocalizedKeys.topup.rawValue) : descEn
            } else {
                detailLabel.text = descKm.isEmpty ? B24PaymentSdkHelper.localized(TopupLocalizedKeys.topup.rawValue) : descKm
            }
            
            setLogoFill(false)
            let placeholder = UIImage(systemName: "arrow.down.backward")
            logo.loadImage(from: transaction.logo, placeholder: placeholder) { success in
                if success {
                    setLogoFill(true)
                }
            }
            logo.tintColor = nil
            amountLabel.textColor = DefaultAppearance.shared.successColor
        } else {
            let value = (transaction.paidTo?.isEmpty == false) ? transaction.paidTo! : "N/A"
            titleLabel.text = value
            detailLabel.text = (language?.lowercased() == "en") ? (transaction.descriptionEn) : (transaction.descriptionKm)
            
            setLogoFill(false)
            logo.image = UIImage(systemName: "arrow.up.left")
            logo.tintColor = DefaultAppearance.shared.dangerColor
            amountLabel.textColor = DefaultAppearance.shared.dangerColor
        }
        
        amountLabel.text = transaction.totalAmountDisplay
        
        NSLayoutConstraint.activate([
            logoBg.leadingAnchor.constraint(equalTo: row.leadingAnchor, constant: 12),
            logoBg.centerYAnchor.constraint(equalTo: row.centerYAnchor),
            logoBg.widthAnchor.constraint(equalToConstant: 40),
            logoBg.heightAnchor.constraint(equalToConstant: 40),
            
            labelStack.leadingAnchor.constraint(equalTo: logoBg.trailingAnchor, constant: 12),
            labelStack.centerYAnchor.constraint(equalTo: row.centerYAnchor),
            
            amountLabel.trailingAnchor.constraint(equalTo: row.trailingAnchor, constant: -12),
            amountLabel.centerYAnchor.constraint(equalTo: row.centerYAnchor),
            amountLabel.leadingAnchor.constraint(greaterThanOrEqualTo: labelStack.trailingAnchor, constant: 10)
        ])
        
        return row
    }

    // Add a helper method to get currency symbol
    private func getCurrencySymbol(for currency: String) -> String {
        
        var currencyCodeSymbol="";
        
        if(SDKVariableSetting.isDislpayCurrencySymbol){
            currencyCodeSymbol=currencySymbol
        }else{
            currencyCodeSymbol=currencyCode
        }
        
        switch currency.uppercased() {
        case "USD":
            return currencyCodeSymbol
        case "KHR":
            return currencyCodeSymbol
        default:
            return currency
        }
    }

    // Update the addPadding method to handle different currencies
    func addPadding(to textField: UITextField) {
        // Currency prefix — bold 15pt, navy color
        let currencySymbol = getCurrencySymbol(for: currency)
        let currencyLabel = UILabel()
        currencyLabel.text = currencySymbol
        currencyLabel.font = FontManager.shared.boldFont(forLanguage: "en", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.buttonText)
        currencyLabel.textColor = DefaultAppearance.shared.secondaryLabelColor
        currencyLabel.sizeToFit()

        let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: currencyLabel.frame.width + 24, height: textField.frame.height))
        currencyLabel.frame = CGRect(x: 12, y: (textField.frame.height - currencyLabel.frame.height) / 2, width: currencyLabel.frame.width, height: currencyLabel.frame.height)
        paddingView.addSubview(currencyLabel)
        textField.leftView = paddingView
        textField.leftViewMode = .always

        // Clear button — xmark inside a circle, color adapts to dark/light mode
        let clearCircle = UIView(frame: CGRect(x: 0, y: 0, width: 28, height: 28))
        clearCircle.backgroundColor = DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.08)
        clearCircle.layer.cornerRadius = 14
        clearCircle.clipsToBounds = true

        let clearButton = UIButton(type: .custom)
        clearButton.setImage(UIImage(systemName: "xmark")?.withConfiguration(UIImage.SymbolConfiguration(pointSize: 10, weight: .semibold)), for: .normal)
        clearButton.tintColor = DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.5)
        clearButton.frame = clearCircle.bounds
        clearButton.addTarget(self, action: #selector(clearTextField(_:)), for: .touchUpInside)
        clearCircle.addSubview(clearButton)

        let buttonPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: textField.frame.height))
        clearCircle.center = CGPoint(x: 18, y: textField.frame.height / 2)
        buttonPaddingView.addSubview(clearCircle)

        textField.rightView = buttonPaddingView
        textField.rightViewMode = .always
    }
    
    // Selector method to clear the text field
    @objc func clearTextField(_ sender: UIButton) {
        inputAmount.text = "0"
        topUpAmount = "0"

        if let indexPaths = amountCollectionView.indexPathsForSelectedItems {
            for indexPath in indexPaths {
                amountCollectionView.deselectItem(at: indexPath, animated: true)
            }
        }
        defaultSelectedIndex = IndexPath(row: -1, section: -1)
        amountCollectionView.reloadData()

        if !inputAmount.isFirstResponder {
            inputAmount.becomeFirstResponder()
        }
    }

    // Update collection view methods to use currentAmountList
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return currentAmountList.count
    }

//    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//        let cell = amountCollectionView.dequeueReusableCell(withReuseIdentifier: "AmountViewCell", for:indexPath) as! AmountViewCell
//
//        let amount = amountList[indexPath.row]
//        
//        configAmountCell(cell, with: amount)
//        
//        // Highlight the default selected cell
//        if indexPath == defaultSelectedIndex {
//            cell.container.backgroundColor = DefaultAppearance.shared.primaryColor
//            cell.amountLabel.textColor = DefaultAppearance.shared.onPrimaryColor
//        } else {
//            cell.container.backgroundColor = DefaultAppearance.shared.cardColor
//        }
//        
//        return cell
//        
//    }


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = amountCollectionView.dequeueReusableCell(withReuseIdentifier: "AmountViewCell", for: indexPath) as! AmountViewCell

        let amount = currentAmountList[indexPath.row]
        configAmountCell(cell, with: amount)
        
        cell.amountLabel.font = FontManager.shared.regularFont(forLanguage: language ?? "km",fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.contentText)

        if indexPath == defaultSelectedIndex {
            cell.container.backgroundColor = DefaultAppearance.shared.primaryColor
            cell.amountLabel.textColor = DefaultAppearance.shared.onPrimaryColor
            cell.amountLabel.font = FontManager.shared.boldFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.buttonText)
            cell.container.setBorder(color: DefaultAppearance.shared.primaryColor, width: 1.5, cornerRadius: 20)
            cell.container.layer.shadowColor = DefaultAppearance.shared.primaryColor.cgColor
            cell.container.layer.shadowOffset = CGSize(width: 0, height: 2)
            cell.container.layer.shadowRadius = 8
            cell.container.layer.shadowOpacity = 0.3
        } else {
            cell.container.backgroundColor = DefaultAppearance.shared.cardColor
            cell.amountLabel.textColor = DefaultAppearance.shared.primaryLabelColor
            cell.amountLabel.font = FontManager.shared.regularFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.buttonText)
            cell.container.setBorder(color: DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.12), width: 1.5, cornerRadius: 20)
            cell.container.layer.shadowOpacity = 0
        }

        return cell
    }

//    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//        if let cell = collectionView.cellForItem(at: indexPath) as? AmountViewCell {
//            cell.container.backgroundColor = DefaultAppearance.shared.primaryColor
//            cell.amountLabel.textColor = DefaultAppearance.shared.onPrimaryColor
//        }
//
//        topUpAmount = amountList[indexPath.row]
//        inputAmount.text = topUpAmount
//
//        // Reapply padding to ensure currency symbol is correctly displayed
//        self.addPadding(to: inputAmount)
//    }


    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if defaultSelectedIndex != indexPath,
           defaultSelectedIndex.row >= 0,
           defaultSelectedIndex.section >= 0 {
            collectionView.deselectItem(at: defaultSelectedIndex, animated: false)
        }

        defaultSelectedIndex = indexPath
        collectionView.reloadData()

        topUpAmount = currentAmountList[indexPath.row]
        inputAmount.text = topUpAmount

        self.addPadding(to: inputAmount)
    }

    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        if defaultSelectedIndex == indexPath {
            defaultSelectedIndex = IndexPath(row: -1, section: -1)
            collectionView.reloadData()
        }
    }
    
    
    func configAmountCell(_ cell: AmountViewCell, with amount: String) {
        cell.container.backgroundColor = DefaultAppearance.shared.cardColor
        cell.amountLabel.text = amount
        cell.amountLabel.font = FontManager.shared.regularFont(forLanguage: language ?? "km", fontFromconfig: DefaultAppearance.shared.fontEnglish, size: FixFontSize.buttonText)
        cell.amountLabel.textColor = DefaultAppearance.shared.primaryLabelColor
        cell.container.setBorder(color: DefaultAppearance.shared.primaryLabelColor.withAlphaComponent(0.12), width: 1.5, cornerRadius: 20)
        cell.container.layer.shadowOpacity = 0
    }
    
    
    @IBAction func okButtonAction(_ sender: Any) {
        view.endEditing(true)
        topupWallet()
        
//        let storyboard = UIStoryboard(name: "InstantPaymentMethodView", bundle: B24PaymentSdkHelper.frameworkBundle())
//        let vc = storyboard.instantiateViewController(withIdentifier: "SuccessScreenViewController") as! SuccessScreenViewController
//       // vc.transactionSuccess = transaction
//        if let navigationController = self.navigationController {
//            navigationController.pushViewController(vc, animated: true)
//        } else {
//            // If no navigation controller, you can either show an error or fallback to presenting modally
//            print("Navigation Controller not found.")
//        }
        
    }
    
    func topupWallet(){
        
       // print("====TOPUP AMOUNT \(String(describing: topUpAmount))")
        
        let textToUse = inputAmount.text ?? topUpAmount ?? "0"
        let amountWithoutComma = textToUse.replacingOccurrences(of: ",", with: "")
        
        let amount = Decimal(string: amountWithoutComma)
        
        if(amount == 0 || (currency=="KHR" && amount ?? 0 <= 100)){
            B24PaymentSdkHelper.errorSnackbar(
                    view: view,
                message: B24PaymentSdkHelper.localized(SnackBarLocalizedKeys.amount_zero.rawValue),
                                                forBottomSheet: false
                                            )
            
            return
        }
        
      //  print("amount is : \(String(describing: amount))")
        
        let payload = TopUp(id: walletId, amount: amount ?? 0.0)
        
        do {
            let jsonData = try JSONEncoder().encode(payload)
            guard let jsonString = String(data: jsonData, encoding: .utf8) else {
                showError(message: "Failed to create payload")
                return
            }

            let encryptedText = try EncryptionHelper.encryptHMACAES(
                plainText: jsonString,
                secretKey: SDKVariableSetting.walletSecretKey
            )
           
            sendRequestTopup(encrypt: encryptedText)

        } catch {
            showError(message: "Encryption failed: \(error.localizedDescription)")
        }
        
    }
    
    //MARK: request Topup
    func sendRequestTopup(encrypt:String){
        guard NetworkMonitor.shared.isConnected else {
            if !isWaitingForConnection {
                isWaitingForConnection = true
                
                // Start monitoring on-demand since we found we are offline
                setupNetworkMonitoring()
                NetworkMonitor.shared.startMonitoring()
                B24PaymentSdkHelper.showNoInternetPopup(on: self) { [weak self] in
                    guard let self = self else { return }
                    self.isWaitingForConnection = false
                    B24PaymentSdkHelper.hideNoInternetPopup(from: self, showSuccess: false)
                }
            }
            return
        }
        let progressDiglog = CustomLoadingView.show(in: self)
        
        AF.request(WalletRouter.topUpWallet(encrypted: encrypt))
            .validate().responseData{
               response in
                switch response.result{
                    case .success(let data):
                    progressDiglog.dismiss()
                    self.isWaitingForConnection = false
                    B24PaymentSdkHelper.removePersistentSnackbar(from: self.view)
                    
                    // Stop monitoring on success if it was running
                    NetworkMonitor.shared.stopMonitoring()
                        do{
                            let decodedData = try JSONDecoder().decode(ApiResponse<WalletResponseData>.self, from: data)
                            
                            if decodedData.code == StatusCode.succcess.rawValue{
                                
                                guard let encrypted = decodedData.data.encrypted else {
                                    // handle error properly — e.g., throw custom error or show alert
                                    print("❌ Encrypted value is null")
                                    return
                                }
                                
                                let decryptText = try EncryptionHelper.decryptHMACAES(encryptedBase64: encrypted, secretKey:  SDKVariableSetting.walletSecretKey)
                                
                                let decryptedData = decryptText.data(using: .utf8)!
                                
                                // Decode the data into ApiResponse model
                                let checkout = try JSONDecoder().decode(TopUpResponseModel.self, from: decryptedData)
                                
                                //set flag for top-up transaction
                                TopUpView.isTopUpTransaction = true
                                
                                let isProduction = SharedPreferenceManager.getBool(forKey: SharePrefKey.isProduction.rawValue)
                                                               
                                let testEnv = SharedPreferenceManager.get(forKey: SharePrefKey.environment.rawValue) as? String ?? "DEMO"
                                
                               
                                B24PaymentSdk().initSdk(controller: self,
                                                      transactionId: checkout.tranId,
                                                      refererKey: SDKVariableSetting.xRefererKey,
                                                      language: self.language,
                                                      darkMode:SDKVariableSetting.isDarkMode,
                                                      isProduction: isProduction,
                                                      testingEnv:testEnv
                                                      
                                )
                            }else{
                                let message = (self.language?.lowercased() == "en") ? decodedData.message : decodedData.messageKh
                                
                                B24PaymentSdkHelper.errorSnackbar(view: self.view,
                                                                  message: message )
                            }
                            
                            
                            
//                              print("Transaction ID: \(checkout.tranId)")
//                              print("Identity Code: \(checkout.identityCode)")
//                              print("Payment Link: \(checkout.paymentLink)")
//                              print("KHQR String: \(checkout.khqrString)")

//                            print("===========>\(decodedData)")
//                            print("===========>\(decryptText)")
                        }catch {
                            print("Decode Error: \(error)")
                        }
                    
                    case .failure(let error):
                        progressDiglog.dismiss()
                        
                        if !self.isWaitingForConnection {
                            self.isWaitingForConnection = true
                            
                            // Start monitoring on-demand since the request failed
                            self.setupNetworkMonitoring()
                            NetworkMonitor.shared.startMonitoring()
                            
                            B24PaymentSdkHelper.showNoInternetPopup(on: self) { [weak self] in
                                guard let self = self else { return }
                                self.isWaitingForConnection = false
                                B24PaymentSdkHelper.hideNoInternetPopup(from: self, showSuccess: false)
                            }
                        }
                        print("ERROR \(error)")
                }
            }
    }
    
    private func showError(message: String) {
        DispatchQueue.main.async {
            let alert = UIAlertController(
                title: "Error",
                message: message,
                preferredStyle: .alert
            )
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            self.present(alert, animated: true)
        }
    }
    
}

extension TopUpView: UICollectionViewDelegateFlowLayout {
    // Set cell size
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let itemsPerRow: CGFloat = 3
        let sectionInsets = self.collectionView(collectionView, layout: collectionViewLayout, insetForSectionAt: indexPath.section)
        let interItemSpacing = self.collectionView(collectionView, layout: collectionViewLayout, minimumInteritemSpacingForSectionAt: indexPath.section)
        
        let totalInset = sectionInsets.left + sectionInsets.right + (interItemSpacing * (itemsPerRow - 1))
        let availableWidth = collectionView.frame.width - totalInset
        let itemWidth = floor(availableWidth / itemsPerRow)
        
        return CGSize(width: itemWidth, height: 45)
    }

    // Set section insets
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
    }

    // Set spacing between rows
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 16
    }

    // Set spacing between items in the same row
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 12
    }
}

// MARK: - UIGestureRecognizerDelegate
extension TopUpView {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        // Ignore background dismiss gesture when tapping the OK button
        if touch.view == buttonOk {
            return false
        }
        
        if gestureRecognizer is UIPanGestureRecognizer,
            gestureRecognizer.view == transactionBottomSheet?.view {

            let location = touch.location(in: view)
            return transactionBottomSheet?.view.frame.contains(location) ?? true
        }
        return true
    }
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // Allow main scroll view to work with nested scroll views
        if let scrollView = otherGestureRecognizer.view as? UIScrollView {
            // If it's the main scroll view or recent transactions scroll view, allow simultaneous gestures
            if scrollView == mainScrollView || scrollView == recentTransactionPreview {
                return true
            }
        }
        
        // Handle bottom sheet gestures
        if gestureRecognizer is UIPanGestureRecognizer && gestureRecognizer.view == transactionBottomSheet?.view {
            if let _ = otherGestureRecognizer.view as? UIScrollView {
                let panGesture = gestureRecognizer as! UIPanGestureRecognizer
                let translation = panGesture.translation(in: view)
                return shouldHandleBottomSheetGesture(gesture: panGesture, translation: translation)
            }
            return false
        }
        return true
    }
}

// MARK: - TransactionsViewDelegate
extension TopUpView {
    func shouldCollapseBottomSheet() {
        dismissBottomSheet()
    }
    
    func shouldExpandBottomSheet() {
        guard currentDetentState == .medium else { return }
        currentDetentState = .large
        animateToDetent(.large, animated: true)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            self.transactionBottomSheet?.setBottomSheetState(collapsed: false)
        }
        triggerHapticFeedback()
    }
    
    @objc private func handleBackgroundTap() {
        dismissBottomSheet()
    }

    private func addDimBackground() {
        guard let windowScene = UIApplication.shared.connectedScenes
            .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
            let window = windowScene.windows.first(where: { $0.isKeyWindow }) else {
            return
        }
        if window.viewWithTag(999) != nil { return }

        let dimView = UIView()
        dimView.tag = 999
        dimView.backgroundColor = UIColor.black.withAlphaComponent(0.35)
        dimView.translatesAutoresizingMaskIntoConstraints = false
        dimView.alpha = 0

        let tap = UITapGestureRecognizer(target: self, action: #selector(handleBackgroundTap))
        dimView.addGestureRecognizer(tap)

        window.insertSubview(dimView, belowSubview: transactionBottomSheet!.view)

        NSLayoutConstraint.activate([
            dimView.topAnchor.constraint(equalTo: view.topAnchor),
            dimView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            dimView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            dimView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])

        UIView.animate(withDuration: 0.25) {
            dimView.alpha = 1
        }
    }

    private func removeDimBackground() {
        guard let windowScene = UIApplication.shared.connectedScenes
            .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
            let window = windowScene.windows.first(where: { $0.isKeyWindow }),
            let dimView = window.viewWithTag(999) else {
            return
        }

        UIView.animate(withDuration: 0.2, animations: {
            dimView.alpha = 0
        }) { _ in
            dimView.removeFromSuperview()
        }
    }

}
    private func removeDimBackground() {
        guard let windowScene = UIApplication.shared.connectedScenes
            .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
            let window = windowScene.windows.first(where: { $0.isKeyWindow }),
            let dimView = window.viewWithTag(999) else {
            return
        }

        UIView.animate(withDuration: 0.2, animations: {
            dimView.alpha = 0
        }) { _ in
            dimView.removeFromSuperview()
        }
    }
