using System; using System.Collections.Generic; using System.Text; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using UnityEngine.Networking; using TMPro; using Newtonsoft.Json; using CommanderAILab.Models; using CommanderAILab.Services; namespace CommanderAILab.UI { /// /// DeckBuilder scene — deck list, card search, drag-to-add, mana curve, /// color-identity pie, save/delete, export to Simulator. /// public class DeckBuilderController : MonoBehaviour { // ── Navigation ─────────────────────────────────────────────────────── [Header("Navigation")] [SerializeField] private Button backButton; [SerializeField] private Button exportToSimButton; // ── Deck List Panel (left) ──────────────────────────────────────────── [Header("Deck List Panel")] [SerializeField] private Transform deckListParent; [SerializeField] private GameObject deckRowPrefab; [SerializeField] private Button newDeckButton; [SerializeField] private TMP_InputField deckNameInput; // ── Active Deck Panel (center) ──────────────────────────────────────── [Header("Active Deck")] [SerializeField] private TMP_Text deckTitleText; [SerializeField] private TMP_Text cardCountText; // "99 / 100" [SerializeField] private GameObject validationIndicator; // green/red [SerializeField] private TMP_Text validationText; [SerializeField] private Transform deckCardListParent; [SerializeField] private GameObject deckCardRowPrefab; [SerializeField] private Button saveDeckButton; [SerializeField] private Button deleteDeckButton; // ── Commander search ────────────────────────────────────────────────── [Header("Commander Search")] [SerializeField] private TMP_InputField commanderSearchInput; [SerializeField] private Button commanderSearchButton; [SerializeField] private TMP_Dropdown colorIdentityDropdown; [SerializeField] private Transform commanderResultParent; [SerializeField] private GameObject commanderResultRowPrefab; [SerializeField] private TMP_Text selectedCommanderText; // ── Card Search Panel (right) ───────────────────────────────────────── [Header("Card Search Panel")] [SerializeField] private TMP_InputField cardSearchInput; [SerializeField] private Button cardSearchButton; [SerializeField] private Transform cardSearchResultParent; [SerializeField] private GameObject cardSearchRowPrefab; // ── Mana Curve Chart ────────────────────────────────────────────────── [Header("Mana Curve")] [SerializeField] private Transform manaCurveBarParent; // holds bar GameObjects [SerializeField] private GameObject manaCurveBarPrefab; // ── Color Identity Pie ──────────────────────────────────────────────── [Header("Color Pie")] [SerializeField] private Image[] colorPieSlices; // W U B R G C — 6 images // ── Error ───────────────────────────────────────────────────────────── [Header("Error")] [SerializeField] private GameObject errorPanel; [SerializeField] private TMP_Text errorText; [SerializeField] private Button retryButton; // ── State ───────────────────────────────────────────────────────────── private List _decks = new(); private DeckModel _activeDeck; private List _deckCards = new(); private CardModel _commander; private bool _isDirty; private readonly List _deckRowObjects = new(); private readonly List _deckCardRowObjects = new(); private readonly List _searchRowObjects = new(); private readonly List _commanderRowObjects = new(); // ── Lifecycle ───────────────────────────────────────────────────────── private void Start() { backButton.onClick.AddListener(() => { if (_isDirty) PromptSave(); else SceneManager.LoadScene("MainMenu"); }); exportToSimButton.onClick.AddListener(OnExportToSim); newDeckButton.onClick.AddListener(OnNewDeck); saveDeckButton.onClick.AddListener(OnSaveDeck); deleteDeckButton.onClick.AddListener(OnDeleteDeck); cardSearchButton.onClick.AddListener(OnCardSearch); cardSearchInput.onSubmit.AddListener(_ => OnCardSearch()); commanderSearchButton.onClick.AddListener(OnCommanderSearch); commanderSearchInput.onSubmit.AddListener(_ => OnCommanderSearch()); retryButton.onClick.AddListener(LoadDecks); errorPanel.SetActive(false); // Pick up any card passed from Collection scene string pending = PlayerPrefs.GetString("PendingAddCard", ""); if (!string.IsNullOrEmpty(pending)) { PlayerPrefs.DeleteKey("PendingAddCard"); try { var card = JsonConvert.DeserializeObject(pending); if (card != null) AddCardToDeck(card); } catch { } } LoadDecks(); } // ── Deck List ───────────────────────────────────────────────────────── private void LoadDecks() { errorPanel.SetActive(false); ApiClient.Instance.GetDecks( json => { try { var wrapper = JsonConvert.DeserializeObject(json); _decks = wrapper?.decks ?? new List(); } catch { _decks = new List(); } RebuildDeckList(); }, err => ShowError($"Failed to load decks:\n{err}")); } private void RebuildDeckList() { foreach (var go in _deckRowObjects) if (go) Destroy(go); _deckRowObjects.Clear(); foreach (var deck in _decks) { var row = Instantiate(deckRowPrefab, deckListParent); _deckRowObjects.Add(row); var label = row.GetComponentInChildren(); if (label) label.text = deck.name; var btn = row.GetComponentInChildren