import SwiftUI
import UIKit

/// Enables full-screen interactive swipe-back gesture (not just the edge)
/// when `.navigationBarBackButtonHidden(true)` is used in SwiftUI.
///
/// How it works: finds the UINavigationController's `interactivePopGestureRecognizer`,
/// extracts its internal target/action, and adds a new full-width UIPanGestureRecognizer
/// with the same target/action to the navigation controller's view.
struct SwipeBackGestureEnabler: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
        SwipeBackController()
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}

    private final class SwipeBackController: UIViewController, UIGestureRecognizerDelegate {
        private var addedGesture = false

        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            guard !addedGesture else { return }
            addedGesture = true

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

            // Re-enable system gesture (in case it was disabled)
            edgeGesture.isEnabled = true

            // Create a full-width pan gesture with the same internal target
            let fullWidthGesture = UIPanGestureRecognizer()
            fullWidthGesture.setValue(targets, forKey: "targets")
            fullWidthGesture.delegate = self
            nav.view.addGestureRecognizer(fullWidthGesture)
        }

        // MARK: - UIGestureRecognizerDelegate

        func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            guard let pan = gestureRecognizer as? UIPanGestureRecognizer else { return false }
            let velocity = pan.velocity(in: pan.view)
            // Only allow right-swipe (positive X) and primarily horizontal
            return velocity.x > 0 && abs(velocity.x) > abs(velocity.y)
        }

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

extension View {
    /// Restores the swipe-back gesture from anywhere on screen
    /// after hiding the default back button.
    func enableSwipeBack() -> some View {
        background(SwipeBackGestureEnabler())
    }
}
