//
//  RNSwipeableView.swift
//  humand
//
//  Created by Oleksandr Shumihin on 16/2/26.
//  Copyright © 2026 Humand. All rights reserved.
//

import Foundation
import UIKit

@objc(RNGesturePressableView)
final class RNGesturePressableView: UIView, UIGestureRecognizerDelegate {
  @objc var onLongPressCallback: RCTDirectEventBlock?
  @objc var onDoubleTapCallback: RCTDirectEventBlock?

  @objc var enableHapticFeedback: Bool = false
  @objc var gestureOffsetRight: Double = 0.0
  @objc var gestureOffsetLeft: Double = 0.0

  private lazy var doubleTapGR: UITapGestureRecognizer = {
    let gr = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(_:)))
    gr.numberOfTapsRequired = 2
    gr.delegate = self

    gr.cancelsTouchesInView = true // If true, once this gesture is recognized, touches in subviews are cancelled.

    gr.delaysTouchesBegan = true // If true, subviews won’t receive touchesBegan until this gesture fails.
    gr.delaysTouchesEnded = true // If true, subviews won’t receive touchesEnded until this gesture fails.
    return gr
  }()

  private lazy var longPressGR: UILongPressGestureRecognizer = {
    let gr = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
    gr.minimumPressDuration = 0.24
    gr.delegate = self

    gr.cancelsTouchesInView = true
    gr.delaysTouchesBegan = true
    return gr
  }()

  @objc
  override init(frame: CGRect) {
    super.init(frame: frame)
    setup()
  }

  @objc
  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setup()
  }

  private func setup() {
    isUserInteractionEnabled = true
    addGestureRecognizer(doubleTapGR)
    addGestureRecognizer(longPressGR)
  }

  @objc private func handleDoubleTap(_ gr: UITapGestureRecognizer) {
    guard gr.state == .ended else { return }

    triggerHapticIfNeeded()
    onDoubleTapCallback?(getEventPosition(gr: gr))
  }

  @objc private func handleLongPress(_ gr: UILongPressGestureRecognizer) {
    if gr.state == .began {
      triggerHapticIfNeeded()
      onLongPressCallback?(getEventPosition(gr: gr))
    }
  }

  private func triggerHapticIfNeeded() {
    if enableHapticFeedback {
      let generator = UIImpactFeedbackGenerator(style: .medium)
      generator.prepare()
      generator.impactOccurred()
    }
  }

  private func getEventPosition(gr: UIGestureRecognizer) -> [String: CGFloat] {
    let point = gr.location(in: self)
    let abs = gr.location(in: self.window)
    return [
      "x": point.x,
      "y": point.y,
      "absoluteX": abs.x,
      "absoluteY": abs.y,
    ]
  }

  // if true  -> both gestures can recognize together
  // if false -> only one gesture can win
  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                         shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
  {
    return true
  }

  // if true  -> this gesture waits until the other fails
  // if false -> this gesture does not wait
  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                         shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool
  {
    return false
  }

  // if true  -> other gestures must wait until this one fails
  // if false -> other gestures do not wait
  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                         shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool
  {
    return false
  }

  // Called before the gesture recognizer begins tracking a touch.
  // Return false to ignore touches in restricted areas and let them
  // propagate to other gesture recognizers or views.
  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                         shouldReceive touch: UITouch) -> Bool
  {
    guard let window = self.window else {
      return true
    }

    let point = touch.location(in: window)
    let screenWidth = window.bounds.width

    // Left dead zone
    if point.x < gestureOffsetLeft {
      return false
    }

    // Right dead zone
    if point.x > screenWidth - gestureOffsetRight {
      return false
    }

    // For exclusive child regions: block only double-tap so touches arrive immediately,
    // but let long-press through so the context menu still works anywhere in the bubble.
    if gestureRecognizer === doubleTapGR {
      var view = touch.view
      while let v = view, v !== self {
        if v is RNGesturePressableNoDoubleTapView { return false }
        view = v.superview
      }
    }

    return true
  }
}
