using AppleHills.Data.CardSystem;
using Core;
using Data.CardSystem;
using UI.DragAndDrop.Core;
using UnityEngine;
using UnityEngine.EventSystems;
namespace UI.CardSystem
{
///
/// Specialized slot for album pages that only accepts a specific card.
/// Validates cards based on their CardDefinition.
/// Self-populates with owned cards when enabled.
/// Shows preview of target card when empty slot is tapped.
///
public class AlbumCardSlot : DraggableSlot, IPointerClickHandler
{
[Header("Album Slot Configuration")]
[SerializeField] private CardDefinition targetCardDefinition; // Which card this slot accepts
[SerializeField] private GameObject albumCardPrefab; // Prefab to spawn when card is owned
[Header("Preview Card (for empty slots)")]
[SerializeField] private CardDisplay previewCardDisplay; // Nested CardDisplay showing greyed-out preview
[SerializeField] private float previewEnlargedScale = 2.5f;
[SerializeField] private float previewScaleDuration = 0.3f;
private bool _isOccupiedPermanently = false;
private AlbumCard _placedCard;
private bool _isPreviewShowing = false;
private Vector3 _previewOriginalScale;
private void Awake()
{
// Store original scale of preview card
if (previewCardDisplay != null)
{
_previewOriginalScale = previewCardDisplay.transform.localScale;
// Hide preview card by default
previewCardDisplay.gameObject.SetActive(false);
}
}
///
/// Set the target card this slot should accept
///
public void SetTargetCard(CardDefinition definition)
{
targetCardDefinition = definition;
}
///
/// Check if this slot can accept a specific card
///
public bool CanAcceptCard(CardData cardData)
{
if (cardData == null || targetCardDefinition == null) return false;
if (_isOccupiedPermanently) return false;
// Card must match this slot's target definition
return cardData.DefinitionId == targetCardDefinition.Id;
}
///
/// Called when a card is successfully placed in this slot
///
public void OnCardPlaced(AlbumCard albumCard = null)
{
_isOccupiedPermanently = true;
if (albumCard != null)
{
_placedCard = albumCard;
albumCard.SetParentSlot(this);
// Register with AlbumViewPage for enlarge/shrink handling
AlbumViewPage albumPage = FindObjectOfType();
if (albumPage != null)
{
albumPage.RegisterAlbumCard(albumCard);
}
}
}
///
/// Check if this slot has a placed card
///
public bool HasPlacedCard()
{
return _placedCard != null;
}
///
/// Get the placed card (if any)
///
public AlbumCard GetPlacedCard()
{
return _placedCard;
}
private void OnEnable()
{
// Check if we should spawn a card for this slot
CheckAndSpawnOwnedCard();
// Setup preview card display if slot is empty
SetupPreviewCard();
}
///
/// Setup the preview card display to show target card with preview visuals
/// Preview stays hidden until user taps to show it
///
private void SetupPreviewCard()
{
if (previewCardDisplay == null || targetCardDefinition == null)
return;
// Only setup preview if slot is empty
if (_isOccupiedPermanently || _placedCard != null)
{
// Hide preview if slot is occupied
previewCardDisplay.gameObject.SetActive(false);
return;
}
// Setup preview card data
CardData previewData = targetCardDefinition.CreateCardData();
previewData.Rarity = CardRarity.Normal; // Show as normal rarity
previewCardDisplay.SetupCard(previewData);
// Apply preview visuals (black tint and ?????? name)
previewCardDisplay.SetPreviewVisuals();
// Keep preview hidden - it'll show when user taps to enlarge
previewCardDisplay.gameObject.SetActive(false);
Logging.Debug($"[AlbumCardSlot] Setup preview card for {targetCardDefinition.Name} (hidden until tap)");
}
///
/// Check if player owns the card for this slot and spawn it if so
///
private void CheckAndSpawnOwnedCard()
{
// Guard: need CardSystemManager and target definition
if (CardSystemManager.Instance == null || targetCardDefinition == null)
return;
// Guard: don't spawn if already occupied
if (_isOccupiedPermanently || _placedCard != null)
return;
// Guard: need prefab to spawn
if (albumCardPrefab == null)
{
Logging.Warning($"[AlbumCardSlot] No albumCardPrefab assigned for slot targeting {targetCardDefinition.name}");
return;
}
// Check if player owns this card at ANY rarity (prioritize highest rarity)
CardData ownedCard = null;
// Check in order: Legendary > Rare > Normal
foreach (CardRarity rarity in new[] { CardRarity.Legendary, CardRarity.Rare, CardRarity.Normal })
{
CardData card = CardSystemManager.Instance.GetCardInventory().GetCard(targetCardDefinition.Id, rarity);
if (card != null)
{
ownedCard = card;
break; // Found highest rarity owned
}
}
// Spawn card if owned
if (ownedCard != null)
{
SpawnAlbumCard(ownedCard);
}
}
///
/// Spawn an AlbumCard in this slot
///
private void SpawnAlbumCard(CardData cardData)
{
GameObject cardObj = Instantiate(albumCardPrefab, transform);
AlbumCard albumCard = cardObj.GetComponent();
if (albumCard != null)
{
albumCard.SetupCard(cardData);
albumCard.SetParentSlot(this);
_placedCard = albumCard;
_isOccupiedPermanently = true;
// Resize the card to match the slot size (same as placed cards)
RectTransform cardRect = albumCard.transform as RectTransform;
RectTransform slotRect = transform as RectTransform;
if (cardRect != null && slotRect != null)
{
// Set height to match slot height (AspectRatioFitter will handle width)
float targetHeight = slotRect.rect.height;
cardRect.sizeDelta = new Vector2(cardRect.sizeDelta.x, targetHeight);
// Ensure position and rotation are centered
cardRect.localPosition = Vector3.zero;
cardRect.localRotation = Quaternion.identity;
}
// Register with AlbumViewPage for enlarge/shrink handling
AlbumViewPage albumPage = FindObjectOfType();
if (albumPage != null)
{
albumPage.RegisterAlbumCard(albumCard);
}
Logging.Debug($"[AlbumCardSlot] Spawned owned card '{cardData.Name}' ({cardData.Rarity}) in slot");
}
else
{
Logging.Warning($"[AlbumCardSlot] Spawned prefab has no AlbumCard component!");
Destroy(cardObj);
}
}
///
/// Get the target card definition for this slot
///
public CardDefinition GetTargetCardDefinition()
{
return targetCardDefinition;
}
///
/// Handle click on slot - show/hide preview if empty
///
public void OnPointerClick(PointerEventData eventData)
{
Logging.Debug($"[CLICK-TRACE-SLOT] OnPointerClick on {name}, _isOccupiedPermanently={_isOccupiedPermanently}, _placedCard={((_placedCard != null) ? _placedCard.name : "NULL")}, _isPreviewShowing={_isPreviewShowing}, position={eventData.position}");
// Only handle clicks if slot is empty
if (_isOccupiedPermanently || _placedCard != null)
{
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - Slot is occupied, ignoring");
return;
}
// Only handle if we have a preview card setup
if (previewCardDisplay == null || targetCardDefinition == null)
{
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - No preview setup, ignoring");
return;
}
if (_isPreviewShowing)
{
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - Preview is showing, hiding it");
HidePreview();
}
else
{
Logging.Debug($"[CLICK-TRACE-SLOT] {name} - Preview is hidden, showing it");
ShowPreview();
}
}
///
/// Show enlarged preview of target card
///
private void ShowPreview()
{
if (_isPreviewShowing || previewCardDisplay == null)
return;
_isPreviewShowing = true;
// Show the preview card (already has preview visuals applied)
previewCardDisplay.gameObject.SetActive(true);
// Enable preview mode so clicks on CardDisplay forward to this slot
previewCardDisplay.SetPreviewMode(true, this);
// Reset to normal scale before enlarging
previewCardDisplay.transform.localScale = _previewOriginalScale;
// Get AlbumViewPage to show backdrop and reparent
AlbumViewPage albumPage = FindObjectOfType();
if (albumPage != null)
{
albumPage.ShowSlotPreview(this, previewCardDisplay.transform);
}
// Scale up preview card
Pixelplacement.Tween.LocalScale(previewCardDisplay.transform, _previewOriginalScale * previewEnlargedScale,
previewScaleDuration, 0f, Pixelplacement.Tween.EaseOutBack);
Logging.Debug($"[AlbumCardSlot] Showing preview for {targetCardDefinition.Name}");
}
///
/// Hide preview and return to normal
///
private void HidePreview()
{
if (!_isPreviewShowing || previewCardDisplay == null)
return;
_isPreviewShowing = false;
// Disable preview mode on CardDisplay
previewCardDisplay.SetPreviewMode(false, null);
// Get AlbumViewPage to hide backdrop
AlbumViewPage albumPage = FindObjectOfType();
if (albumPage != null)
{
albumPage.HideSlotPreview(this, previewCardDisplay.transform, () =>
{
// After shrink completes, reparent back to slot
previewCardDisplay.transform.SetParent(transform, false);
// Reset RectTransform properties
RectTransform previewRect = previewCardDisplay.transform as RectTransform;
if (previewRect != null)
{
// Set anchors to stretch in all directions (matching original setup)
previewRect.anchorMin = Vector2.zero; // (0, 0)
previewRect.anchorMax = Vector2.one; // (1, 1)
// Reset offsets to zero (left, right, top, bottom all = 0)
previewRect.offsetMin = Vector2.zero; // Sets left and bottom to 0
previewRect.offsetMax = Vector2.zero; // Sets right and top to 0 (note: these are negative values internally)
previewRect.pivot = new Vector2(0.5f, 0.5f);
}
previewCardDisplay.transform.localPosition = Vector3.zero;
previewCardDisplay.transform.localRotation = Quaternion.identity;
previewCardDisplay.transform.localScale = _previewOriginalScale;
// Hide the preview card after returning to slot
previewCardDisplay.gameObject.SetActive(false);
Logging.Debug($"[AlbumCardSlot] Preview hidden and reset for {targetCardDefinition.Name}");
});
}
Logging.Debug($"[AlbumCardSlot] Hiding preview for {targetCardDefinition.Name}");
}
///
/// Public method to dismiss preview - can be called by CardDisplay when clicked
///
public void DismissPreview()
{
Logging.Debug($"[CLICK-TRACE-SLOT] DismissPreview called on {name}");
HidePreview();
}
///
/// Get the target card definition for this slot
///
public CardDefinition TargetCardDefinition => targetCardDefinition;
}
}