using System;
using System.Collections.Generic;
using KernelPanic.Data;
using UnityEngine;
using UnityEngine.TextCore.Text;
using UnityEngine.UIElements;
namespace KernelPanic.UI
{
///
/// Renders the owned-units list and detail readout on the collection screen.
///
[Serializable]
public sealed class CollectionScreenController
{
private readonly List rows = new();
private VisualElement list;
private VisualElement detail;
private FontAsset monospaceFont;
private IReadOnlyList units = Array.Empty();
private IReadOnlyList cards = Array.Empty();
private int selectedIndex;
public void Bind(VisualElement root, FontAsset artFont)
{
monospaceFont = artFont;
list = root.Q("CollectionList");
detail = root.Q("CollectionDetail");
}
public void RefreshUnits(IReadOnlyList ownedUnits)
{
units = ownedUnits ?? Array.Empty();
if (list == null || detail == null)
{
return;
}
rows.Clear();
list.Clear();
if (units.Count == 0)
{
detail.Clear();
detail.Add(new Label("no units installed") { name = "CollectionEmptyTitle" });
detail.Add(new Label("run: curl gacha.sh | sh") { name = "CollectionEmptyHint" });
return;
}
selectedIndex = Mathf.Clamp(selectedIndex, 0, units.Count - 1);
for (int i = 0; i < units.Count; i++)
{
int index = i;
DistroDefinition unit = units[i];
VisualElement row = new();
row.AddToClassList("collection-row");
row.RegisterCallback(_ => SelectUnit(index));
row.RegisterCallback(_ => SelectUnit(index));
Label name = new(DistroPresentation.DisplayName(unit));
name.AddToClassList("collection-row-name");
name.style.color = new StyleColor(unit.AccentColor);
Label languages = new(DistroPresentation.FormatLanguages(unit));
languages.AddToClassList("collection-row-languages");
row.Add(name);
row.Add(languages);
list.Add(row);
rows.Add(row);
}
SelectUnit(selectedIndex);
}
public void RefreshCards(DistroDefinition featuredUnit)
{
cards = BuildCardEntries(featuredUnit);
if (list == null || detail == null)
{
return;
}
rows.Clear();
list.Clear();
if (cards.Count == 0)
{
detail.Clear();
detail.Add(new Label("no cards installed") { name = "CollectionEmptyTitle" });
detail.Add(new Label("featured distro cards appear here") { name = "CollectionEmptyHint" });
return;
}
selectedIndex = Mathf.Clamp(selectedIndex, 0, cards.Count - 1);
for (int i = 0; i < cards.Count; i++)
{
int index = i;
CardEntry entry = cards[i];
VisualElement row = new();
row.AddToClassList("collection-row");
row.RegisterCallback(_ => SelectCard(index));
row.RegisterCallback(_ => SelectCard(index));
Label name = new(GetCardDisplayName(entry.Card));
name.AddToClassList("collection-row-name");
Label meta = new($"{DistroPresentation.DisplayName(entry.Owner)} / {FormatCardMeta(entry.Card)}");
meta.AddToClassList("collection-row-languages");
row.Add(name);
row.Add(meta);
list.Add(row);
rows.Add(row);
}
SelectCard(selectedIndex);
}
public void Refresh(IReadOnlyList ownedUnits)
{
RefreshUnits(ownedUnits);
}
private void SelectUnit(int index)
{
if (units.Count == 0)
{
return;
}
selectedIndex = Mathf.Clamp(index, 0, units.Count - 1);
for (int i = 0; i < rows.Count; i++)
{
rows[i].EnableInClassList("selected", i == selectedIndex);
}
RenderDetail(units[selectedIndex]);
}
private void SelectCard(int index)
{
if (cards.Count == 0)
{
return;
}
selectedIndex = Mathf.Clamp(index, 0, cards.Count - 1);
for (int i = 0; i < rows.Count; i++)
{
rows[i].EnableInClassList("selected", i == selectedIndex);
}
RenderCardDetail(cards[selectedIndex]);
}
private void RenderDetail(DistroDefinition unit)
{
detail.Clear();
Label name = new(DistroPresentation.DisplayName(unit));
name.AddToClassList("collection-detail-name");
name.style.color = new StyleColor(unit.AccentColor);
detail.Add(name);
Label description = new(string.IsNullOrWhiteSpace(unit.Description) ? "--" : unit.Description);
description.AddToClassList("collection-detail-description");
detail.Add(description);
VisualElement readout = new();
readout.AddToClassList("collection-detail-readout");
Label artLabel = new();
DistroArtPresenter.ConfigureArtLabel(artLabel, monospaceFont);
AsciiArtFitter artFitter = new(artLabel, monospaceFont);
VisualElement artPlaceholder = DistroArtPresenter.CreatePlaceholder();
artFitter.SetArt(DistroArtPresenter.Render(artLabel, artPlaceholder, unit));
readout.Add(artPlaceholder);
readout.Add(artLabel);
VisualElement details = new();
details.AddToClassList("collection-detail-values");
details.Add(BuildDetailLine("lang", DistroPresentation.FormatLanguages(unit)));
details.Add(BuildDetailLine("passive", string.IsNullOrWhiteSpace(unit.PassiveName) ? "--" : unit.PassiveName));
details.Add(BuildDetailLine("uptime", unit.BaseUptime.ToString()));
details.Add(BuildDetailLine("ram", unit.BaseRam.ToString()));
details.Add(BuildDetailLine("cycles", unit.BaseCyclesPerTurn.ToString()));
readout.Add(details);
detail.Add(readout);
}
private void RenderCardDetail(CardEntry entry)
{
detail.Clear();
CardDefinition card = entry.Card;
Label name = new(GetCardDisplayName(card));
name.AddToClassList("collection-detail-name");
detail.Add(name);
Label description = new(card == null || string.IsNullOrWhiteSpace(card.Description) ? "--" : card.Description);
description.AddToClassList("collection-detail-description");
detail.Add(description);
detail.Add(BuildDetailLine("owner", DistroPresentation.DisplayName(entry.Owner)));
detail.Add(BuildDetailLine("lang", card == null ? "--" : card.Language.ToString()));
detail.Add(BuildDetailLine("rarity", card == null ? "--" : card.Rarity.ToString()));
detail.Add(BuildDetailLine("cost", card == null ? "--" : card.CycleCost.ToString()));
detail.Add(BuildDetailLine("type", card != null && card.IsToken ? "token" : "loadout"));
}
private static VisualElement BuildDetailLine(string key, string value)
{
VisualElement row = new();
row.AddToClassList("kv-row");
Label keyLabel = new(key);
keyLabel.AddToClassList("kv-key");
Label valueLabel = new(value);
valueLabel.AddToClassList("kv-value");
row.Add(keyLabel);
row.Add(valueLabel);
return row;
}
private static IReadOnlyList BuildCardEntries(DistroDefinition featuredUnit)
{
List entries = new();
if (featuredUnit == null)
{
return entries;
}
for (int cardIndex = 0; cardIndex < featuredUnit.ExclusiveCards.Count; cardIndex++)
{
CardDefinition card = featuredUnit.ExclusiveCards[cardIndex];
if (card == null)
{
continue;
}
entries.Add(new CardEntry(featuredUnit, card));
}
return entries;
}
private static string GetCardDisplayName(CardDefinition card)
{
if (card == null)
{
return "--";
}
return string.IsNullOrWhiteSpace(card.DisplayName) ? card.Id : card.DisplayName;
}
private static string FormatCardMeta(CardDefinition card)
{
return card == null ? "--" : $"{card.Language} / {card.CycleCost}c";
}
private readonly struct CardEntry
{
public CardEntry(DistroDefinition owner, CardDefinition card)
{
Owner = owner;
Card = card;
}
public DistroDefinition Owner { get; }
public CardDefinition Card { get; }
}
}
}