using System; using System.Collections; using AppleHills.Data.CardSystem; using Data.CardSystem; using Pixelplacement; using UI.DragAndDrop.Core; using UnityEngine; namespace UI.CardSystem { /// /// Draggable card for album reveal system. /// Handles both tap and drag-hold interactions for revealing cards. /// Auto-snaps to matching album slot on release/tap. /// public class AlbumCardPlacementDraggable : DraggableObject { [Header("Album Card Settings")] [SerializeField] private FlippableCard flippableCard; [SerializeField] private float holdRevealDelay = 0.1f; private CardData _cardData; private bool _isRevealed = false; private bool _isDragRevealing = false; private bool _waitingForPlacementTap = false; private Coroutine _holdRevealCoroutine; private bool _isHolding = false; // Track if pointer is currently down // Events public event Action OnCardRevealed; public event Action OnCardPlacedInAlbum; public CardData CardData => _cardData; public bool IsRevealed => _isRevealed; public CardZone Zone => _cardData?.Zone ?? CardZone.AppleHills; protected override void Initialize() { base.Initialize(); // Auto-find FlippableCard if not assigned if (flippableCard == null) { flippableCard = GetComponent(); } } /// /// Setup the card data (stores it but doesn't reveal until tapped/dragged) /// public void SetupCard(CardData data) { _cardData = data; if (flippableCard != null) { flippableCard.SetupCard(data); } } /// /// Reveal the card (flip to show front) /// public void RevealCard() { if (_isRevealed) return; _isRevealed = true; if (flippableCard != null) { flippableCard.FlipToReveal(); } OnCardRevealed?.Invoke(this, _cardData); } /// /// Snap to the matching album slot /// public void SnapToAlbumSlot() { if (_cardData == null) { Debug.LogWarning("[AlbumCardPlacementDraggable] Cannot snap to slot - no card data assigned."); return; } // Find all album card slots in the scene AlbumCardSlot[] allSlots = FindObjectsByType(FindObjectsSortMode.None); AlbumCardSlot matchingSlot = null; foreach (var slot in allSlots) { if (slot.CanAcceptCard(_cardData)) { matchingSlot = slot; break; } } if (matchingSlot != null) { SetDraggingEnabled(false); // NEW FLOW: Extract AlbumCard FIRST, then tween it if (flippableCard != null) { AlbumCard extractedCard = flippableCard.ExtractAlbumCard(matchingSlot.transform); if (extractedCard != null) { // Notify slot that card was placed matchingSlot.OnCardPlaced(extractedCard); // NOW tween the extracted AlbumCard into position TweenExtractedCardToSlot(extractedCard, () => { // After animation completes Debug.Log($"[AlbumCardPlacementDraggable] Card placement animation complete for {_cardData.Name}"); // Notify that card was placed OnCardPlacedInAlbum?.Invoke(this, _cardData); // Destroy this wrapper (the AlbumPlacementCard) Destroy(gameObject); }); } else { Debug.LogWarning("[AlbumCardPlacementDraggable] Failed to extract AlbumCard from wrapper!"); } } } else { Debug.LogWarning($"[AlbumCardPlacementDraggable] Could not find matching slot for card '{_cardData.Name}' (Zone: {_cardData.Zone}, Index: {_cardData.CollectionIndex})"); } } /// /// Tween the extracted AlbumCard into its slot position /// Tweens from current size to slot size - AspectRatioFitter handles width /// private void TweenExtractedCardToSlot(AlbumCard card, System.Action onComplete) { Transform cardTransform = card.transform; RectTransform cardRect = cardTransform as RectTransform; if (cardRect != null) { // Get target height from slot RectTransform slotRect = cardTransform.parent as RectTransform; float targetHeight = slotRect != null ? slotRect.rect.height : cardRect.sizeDelta.y; // Tween from current size to target size (AspectRatioFitter will adjust width) Vector2 targetSize = new Vector2(cardRect.sizeDelta.x, targetHeight); Tween.Size(cardRect, targetSize, snapDuration, 0f, Tween.EaseOutBack); // Tween position and rotation to slot center Tween.LocalPosition(cardRect, Vector3.zero, snapDuration, 0f, Tween.EaseOutBack); Tween.LocalRotation(cardTransform, Quaternion.identity, snapDuration, 0f, Tween.EaseOutBack, completeCallback: () => { Debug.Log($"[AlbumCardPlacementDraggable] Tween complete for extracted card {card.name}, final height: {cardRect.sizeDelta.y}"); onComplete?.Invoke(); }); } else { // No RectTransform, just reset and call callback cardTransform.localPosition = Vector3.zero; cardTransform.localRotation = Quaternion.identity; onComplete?.Invoke(); } } protected override void OnPointerDownHook() { base.OnPointerDownHook(); _isHolding = true; // Start hold-reveal timer if card not yet revealed if (!_isRevealed && _holdRevealCoroutine == null) { _holdRevealCoroutine = StartCoroutine(HoldRevealTimer()); } } protected override void OnPointerUpHook(bool longPress) { base.OnPointerUpHook(longPress); Debug.Log($"[CLICK-TRACE-PLACEMENT] OnPointerUpHook on {name}, _wasDragged={_wasDragged}, _isRevealed={_isRevealed}, _waitingForPlacementTap={_waitingForPlacementTap}, longPress={longPress}"); _isHolding = false; // Cancel hold timer if running if (_holdRevealCoroutine != null) { StopCoroutine(_holdRevealCoroutine); _holdRevealCoroutine = null; } // Handle tap (not dragged) if (!_wasDragged) { if (!_isRevealed) { Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - First tap, revealing card"); // First tap: reveal the card RevealCard(); _waitingForPlacementTap = true; } else if (_waitingForPlacementTap) { Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Second tap, snapping to slot"); // Second tap: snap to slot _waitingForPlacementTap = false; SnapToAlbumSlot(); } else { Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Tap after reveal but not waiting for placement tap"); } } else if (_isDragRevealing) { Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Was drag-revealed, auto-snapping"); // Was drag-revealed, auto-snap on release _isDragRevealing = false; SnapToAlbumSlot(); } else { Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Was dragged but no special handling"); } } /// /// Coroutine to reveal card after holding for specified duration /// private IEnumerator HoldRevealTimer() { yield return new WaitForSeconds(holdRevealDelay); // If still holding after delay, reveal the card if (!_isRevealed && _isHolding) { RevealCard(); _isDragRevealing = true; Debug.Log("[AlbumCardDraggable] Card revealed via hold"); } _holdRevealCoroutine = null; } } }