using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AppleHills.Data.CardSystem;
using Data.CardSystem;
using Pixelplacement;
using UI.Core;
using UI.CardSystem.DragDrop;
using UI.DragAndDrop.Core;
using Unity.Cinemachine;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.UI;
namespace UI.CardSystem
{
///
/// UI page for opening booster packs and displaying the cards received.
/// Manages the entire booster opening flow with drag-and-drop interaction.
///
public class BoosterOpeningPage : UIPage
{
[Header("UI References")]
[SerializeField] private CanvasGroup canvasGroup;
[SerializeField] private Button closeButton;
[Header("Booster Management")]
[SerializeField] private GameObject[] boosterPackInstances; // Booster prefabs/instances
[SerializeField] private SlotContainer bottomRightSlots; // Holds waiting boosters
[SerializeField] private DraggableSlot centerOpeningSlot; // Where booster goes to open
[Header("Card Display")]
[SerializeField] private Transform cardDisplayContainer;
[SerializeField] private GameObject flippableCardPrefab; // Placeholder for card backs
[SerializeField] private float cardSpacing = 150f;
[Header("Settings")]
[SerializeField] private float cardRevealDelay = 0.5f;
[SerializeField] private float boosterDisappearDuration = 0.5f;
[SerializeField] private CinemachineImpulseSource impulseSource;
private int _availableBoosterCount;
private BoosterPackDraggable _currentBoosterInCenter;
private List _currentRevealedCards = new List();
private CardData[] _currentCardData;
private int _revealedCardCount;
private bool _isProcessingOpening;
private void Awake()
{
// Make sure we have a CanvasGroup for transitions
if (canvasGroup == null)
canvasGroup = GetComponent();
if (canvasGroup == null)
canvasGroup = gameObject.AddComponent();
// Set up close button
if (closeButton != null)
{
closeButton.onClick.AddListener(OnCloseButtonClicked);
}
// UI pages should start disabled
gameObject.SetActive(false);
}
private void OnDestroy()
{
if (closeButton != null)
{
closeButton.onClick.RemoveListener(OnCloseButtonClicked);
}
// Unsubscribe from slot events
if (centerOpeningSlot != null)
{
centerOpeningSlot.OnOccupied -= OnBoosterPlacedInCenter;
}
// Unsubscribe from booster events
UnsubscribeFromAllBoosters();
}
private void OnCloseButtonClicked()
{
if (UIPageController.Instance != null)
{
UIPageController.Instance.PopPage();
}
}
///
/// Set the number of available booster packs before showing the page
///
public void SetAvailableBoosterCount(int count)
{
_availableBoosterCount = count;
}
public override void TransitionIn()
{
base.TransitionIn();
InitializeBoosterDisplay();
}
public override void TransitionOut()
{
CleanupPage();
base.TransitionOut();
}
///
/// Initialize the booster pack display based on available count
///
private void InitializeBoosterDisplay()
{
Debug.Log($"[BoosterOpeningPage] InitializeBoosterDisplay called with {_availableBoosterCount} boosters available");
if (boosterPackInstances == null || boosterPackInstances.Length == 0)
{
Debug.LogWarning("BoosterOpeningPage: No booster pack instances assigned!");
return;
}
// Calculate how many boosters to show (capped by array size)
int visibleCount = Mathf.Min(_availableBoosterCount, boosterPackInstances.Length);
Debug.Log($"[BoosterOpeningPage] Will show {visibleCount} boosters out of {boosterPackInstances.Length} instances");
// Show/hide boosters and assign to slots
for (int i = 0; i < boosterPackInstances.Length; i++)
{
if (boosterPackInstances[i] == null) continue;
bool shouldShow = i < visibleCount;
Debug.Log($"[BoosterOpeningPage] Booster {i} ({boosterPackInstances[i].name}): shouldShow={shouldShow}, position={boosterPackInstances[i].transform.position}");
boosterPackInstances[i].SetActive(shouldShow);
if (shouldShow)
{
// Get the booster draggable component
BoosterPackDraggable booster = boosterPackInstances[i].GetComponent();
if (booster != null)
{
// Reset state
booster.ResetTapCount();
booster.SetTapToOpenEnabled(false); // Disable tap-to-open until in center
// Subscribe to events
booster.OnReadyToOpen += OnBoosterReadyToOpen;
// Assign to bottom-right slot if slots available
if (bottomRightSlots != null && i < bottomRightSlots.SlotCount)
{
DraggableSlot slot = bottomRightSlots.GetSlotAtIndex(i);
if (slot != null)
{
Debug.Log($"[BoosterOpeningPage] Assigning booster {i} to slot {slot.name} at {slot.transform.position}");
booster.AssignToSlot(slot, false);
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] Slot {i} is null in bottomRightSlots!");
}
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] No slot available for booster {i}. bottomRightSlots={bottomRightSlots}, SlotCount={bottomRightSlots?.SlotCount}");
}
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] Booster {i} has no BoosterPackDraggable component!");
}
}
}
// Subscribe to center slot events
if (centerOpeningSlot != null)
{
centerOpeningSlot.OnOccupied += OnBoosterPlacedInCenter;
Debug.Log($"[BoosterOpeningPage] Subscribed to center slot {centerOpeningSlot.name} at {centerOpeningSlot.transform.position}");
}
else
{
Debug.LogWarning("[BoosterOpeningPage] centerOpeningSlot is null!");
}
}
///
/// Handle when a booster is placed in the center opening slot
///
private void OnBoosterPlacedInCenter(DraggableObject draggable)
{
BoosterPackDraggable booster = draggable as BoosterPackDraggable;
if (booster == null) return;
_currentBoosterInCenter = booster;
// Lock the slot so it can't be dragged out
centerOpeningSlot.SetLocked(true);
// Configure booster for opening (disables drag, enables tapping, resets tap count)
booster.SetInOpeningSlot(true);
// Subscribe to tap events for visual feedback
booster.OnTapped += OnBoosterTapped;
booster.OnReadyToOpen += OnBoosterReadyToOpen;
Debug.Log($"[BoosterOpeningPage] Booster placed in center, ready for {booster.CurrentTapCount} taps");
}
private void OnBoosterTapped(BoosterPackDraggable booster, int currentTaps, int maxTaps)
{
Debug.Log($"[BoosterOpeningPage] Booster tapped: {currentTaps}/{maxTaps}");
// Fire Cinemachine impulse with random velocity (excluding Z)
if (impulseSource != null)
{
// Generate random velocity vector (X and Y only, Z = 0)
Vector3 randomVelocity = new Vector3(
Random.Range(-1f, 1f),
Random.Range(-1f, 1f),
0f
);
// Normalize to ensure consistent strength
randomVelocity.Normalize();
// Generate the impulse with strength 1 and random velocity
impulseSource.GenerateImpulse(randomVelocity);
}
}
///
/// Handle tap-to-place: When player taps a booster in bottom slots, move it to center
///
public void OnBoosterTappedInBottomSlot(BoosterPackDraggable booster)
{
if (_currentBoosterInCenter != null || centerOpeningSlot == null)
return; // Center slot already occupied
// Move booster to center slot
booster.AssignToSlot(centerOpeningSlot, true);
}
///
/// Handle when booster is ready to open (after max taps)
///
private void OnBoosterReadyToOpen(BoosterPackDraggable booster)
{
if (_isProcessingOpening) return;
Debug.Log($"[BoosterOpeningPage] Booster ready to open!");
// Trigger the actual opening sequence
booster.TriggerOpen();
StartCoroutine(ProcessBoosterOpening(booster));
}
///
/// Process the booster opening sequence
///
private IEnumerator ProcessBoosterOpening(BoosterPackDraggable booster)
{
_isProcessingOpening = true;
// Call CardSystemManager to open the pack
if (CardSystemManager.Instance != null)
{
List revealedCardsList = CardSystemManager.Instance.OpenBoosterPack();
_currentCardData = revealedCardsList.ToArray();
// Animate booster disappearing
yield return StartCoroutine(AnimateBoosterDisappear(booster));
// Show card backs
SpawnCardBacks(_currentCardData.Length);
// Wait for player to reveal all cards
yield return StartCoroutine(WaitForCardReveals());
// Check if more boosters available
_availableBoosterCount--;
if (_availableBoosterCount > 0)
{
// Show next booster
yield return StartCoroutine(ShowNextBooster());
}
else
{
// No more boosters, auto-close page
yield return new WaitForSeconds(1f);
if (UIPageController.Instance != null)
{
UIPageController.Instance.PopPage();
}
}
}
_isProcessingOpening = false;
}
///
/// Animate the booster pack disappearing
///
private IEnumerator AnimateBoosterDisappear(BoosterPackDraggable booster)
{
if (booster == null) yield break;
// Scale down and fade out
Transform boosterTransform = booster.transform;
Tween.LocalScale(boosterTransform, Vector3.zero, boosterDisappearDuration, 0f, Tween.EaseInBack);
// Also fade the visual if it has a CanvasGroup
CanvasGroup boosterCg = booster.GetComponentInChildren();
if (boosterCg != null)
{
Tween.Value(1f, 0f, (val) => boosterCg.alpha = val, boosterDisappearDuration, 0f);
}
yield return new WaitForSeconds(boosterDisappearDuration);
// Destroy the booster
Destroy(booster.gameObject);
_currentBoosterInCenter = null;
// Unlock center slot
centerOpeningSlot.SetLocked(false);
}
///
/// Spawn card back placeholders for revealing
///
private void SpawnCardBacks(int count)
{
if (flippableCardPrefab == null || cardDisplayContainer == null)
{
Debug.LogWarning("BoosterOpeningPage: Missing card prefab or container!");
return;
}
_currentRevealedCards.Clear();
_revealedCardCount = 0;
// Calculate positions
float totalWidth = (count - 1) * cardSpacing;
float startX = -totalWidth / 2f;
for (int i = 0; i < count; i++)
{
GameObject cardObj = Instantiate(flippableCardPrefab, cardDisplayContainer);
RectTransform cardRect = cardObj.GetComponent();
if (cardRect != null)
{
cardRect.anchoredPosition = new Vector2(startX + (i * cardSpacing), 0);
}
// Add button to handle reveal on click
Button cardButton = cardObj.GetComponent