using System; using AppleHills.Data.CardSystem; using Core.SaveLoad; using UnityEngine; namespace UI.CardSystem.StateMachine { /// /// Shared context for card states. /// Provides access to common components and data that states need. /// public class CardContext : MonoBehaviour { [Header("Core Components")] [SerializeField] private CardDisplay cardDisplay; [SerializeField] private CardAnimator cardAnimator; private AppleMachine stateMachine; [Header("Card Data")] private CardData cardData; // Injected dependencies private AlbumViewPage albumViewPage; // Public accessors public CardDisplay CardDisplay => cardDisplay; public CardAnimator Animator => cardAnimator; public AppleMachine StateMachine => stateMachine; public Transform RootTransform => transform; public CardData CardData => cardData; /// /// Get the injected AlbumViewPage (null if not set) /// public AlbumViewPage AlbumViewPage => albumViewPage; // Runtime state public bool IsClickable { get; set; } = true; // Original transform data (captured on spawn for shrink animations) public Vector3 OriginalScale { get; private set; } public Vector3 OriginalPosition { get; private set; } public Quaternion OriginalRotation { get; private set; } // Generic drag event - fired when drag starts, consumers decide how to handle based on current state public event Action OnDragStarted; // Generic drag end event - fired when drag ends, consumers decide how to handle based on current state public event Action OnDragEnded; // Booster-specific context (optional, only set for booster flow cards) private BoosterCardContext boosterContext; public BoosterCardContext BoosterContext { get { if (boosterContext == null) boosterContext = new BoosterCardContext(); return boosterContext; } } /// /// Inject AlbumViewPage dependency /// public void SetAlbumViewPage(AlbumViewPage page) { albumViewPage = page; } // Helper method for states/card to signal drag started public void NotifyDragStarted() { OnDragStarted?.Invoke(this); } // Helper method for states/card to signal drag ended public void NotifyDragEnded() { OnDragEnded?.Invoke(this); } private void Awake() { // Auto-find components if not assigned if (cardDisplay == null) cardDisplay = GetComponentInChildren(); if (cardAnimator == null) cardAnimator = GetComponent(); if (stateMachine == null) stateMachine = GetComponentInChildren(); } private void OnEnable() { // Subscribe to CardDisplay click and route to active state if (cardDisplay != null) { cardDisplay.OnCardClicked += HandleCardDisplayClicked; } } private void OnDisable() { if (cardDisplay != null) { cardDisplay.OnCardClicked -= HandleCardDisplayClicked; } } private void HandleCardDisplayClicked(CardDisplay _) { // Gate by clickability if (!IsClickable) return; if (stateMachine == null || stateMachine.currentState == null) return; var handler = stateMachine.currentState.GetComponent(); if (handler != null) { handler.OnCardClicked(this); } } /// /// Setup the card with data /// public void SetupCard(CardData data) { cardData = data; // Reset booster context if it exists if (boosterContext != null) { boosterContext.Reset(); } // Capture original transform for shrink animations. // If current scale is ~0 (pop-in staging), default to Vector3.one. var currentScale = transform.localScale; if (currentScale.x < 0.01f && currentScale.y < 0.01f && currentScale.z < 0.01f) { OriginalScale = Vector3.one; } else { OriginalScale = currentScale; } OriginalPosition = transform.localPosition; OriginalRotation = transform.localRotation; if (cardDisplay != null) { cardDisplay.SetupCard(data); } } /// /// Update card data without re-capturing original transform values. /// Use this when assigning data to an already-initialized card (e.g., pending cards on drag). /// This prevents changing OriginalScale when the card is already correctly sized. /// public void UpdateCardData(CardData data) { cardData = data; // Reset booster context if it exists if (boosterContext != null) { boosterContext.Reset(); } // Don't re-capture OriginalScale/Position/Rotation // This preserves the transform values captured during initial setup if (cardDisplay != null) { cardDisplay.SetupCard(data); } } /// /// Get the card display component /// public CardDisplay GetCardDisplay() => cardDisplay; } }