using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
namespace RR.Common.UI
{
///
/// Модальное окно с правилами игры.
/// Поддерживает несколько страниц с переключением физическими кнопками влево/вправо.
///
public class RulesModal : Modal
{
// ───────────────────────── Страницы ─────────────────────────
[Header("Страницы правил")]
[Tooltip("Список страниц правил. Каждая страница — это отдельный GameObject, " +
"который будет показываться/скрываться при переключении.")]
[SerializeField] private List pages = new();
// ───────────────────────── Навигация ─────────────────────────
[Header("Навигация (Input System)")]
[Tooltip("InputAction навигации (Navigate, тип Value/Vector2)")]
[SerializeField] private InputActionReference navigateAction;
[Tooltip("Порог срабатывания по оси X (0..1)")]
[SerializeField] private float deadZone = 0.5f;
[Tooltip("Зацикливать навигацию (с последней страницы на первую и наоборот)")]
[SerializeField] private bool loop;
// ───────────────────────── Индикатор ─────────────────────────
[Header("Индикатор страниц (опционально)")]
[Tooltip("Текст с номером страницы (например '2 / 5'). Может быть null.")]
[SerializeField] private TMP_Text pageIndicatorText;
[Tooltip("Формат текста индикатора. {0} — текущая, {1} — всего.")]
[SerializeField] private string pageIndicatorFormat = "{0} / {1}";
[Tooltip("Контейнер с точками-индикаторами. Дочерние объекты = точки. Может быть null.")]
[SerializeField] private Transform dotsContainer;
[Tooltip("Цвет активной точки")]
[SerializeField] private Color dotActiveColor = Color.white;
[Tooltip("Цвет неактивной точки")]
[SerializeField] private Color dotInactiveColor = new Color(1f, 1f, 1f, 0.35f);
[Header("Стрелки навигации (опционально)")]
[Tooltip("Изображение стрелки 'назад'. Скрывается, если предыдущей страницы нет.")]
[SerializeField] private RawImage prevArrowImage;
[Tooltip("Изображение стрелки 'вперёд'. Скрывается, если следующей страницы нет.")]
[SerializeField] private RawImage nextArrowImage;
// ───────────────────────── Состояние ─────────────────────────
private int _currentPage;
private bool _axisHeld;
/// Текущий индекс страницы (0-based).
public int CurrentPage => _currentPage;
/// Общее количество страниц.
public int PageCount => pages.Count;
/// Вызывается при смене страницы. Параметр — новый индекс.
public event Action OnPageChanged;
// ───────────────────────── Lifecycle ─────────────────────────
protected override void OnEnable()
{
base.OnEnable();
ShowPage(0);
if (navigateAction != null && navigateAction.action != null)
{
navigateAction.action.Enable();
navigateAction.action.performed += OnNavigatePerformed;
navigateAction.action.canceled += OnNavigateCanceled;
}
}
protected override void OnDisable()
{
if (navigateAction != null && navigateAction.action != null)
{
navigateAction.action.performed -= OnNavigatePerformed;
navigateAction.action.canceled -= OnNavigateCanceled;
}
_axisHeld = false;
base.OnDisable();
}
protected override void OnReturnedToTop()
{
_axisHeld = false;
UpdateIndicator();
}
// ───────────────────────── Ввод (Input System) ─────────────────────────
private void OnNavigatePerformed(InputAction.CallbackContext ctx)
{
float x = ctx.ReadValue().x;
if (Mathf.Abs(x) < deadZone)
{
_axisHeld = false;
return;
}
if (_axisHeld) return;
_axisHeld = true;
if (x < 0f)
PrevPage();
else
NextPage();
}
private void OnNavigateCanceled(InputAction.CallbackContext ctx)
{
_axisHeld = false;
}
// ───────────────────────── Навигация ─────────────────────────
/// Перейти на предыдущую страницу.
public void PrevPage()
{
if (pages.Count == 0) return;
int target = _currentPage - 1;
if (target < 0)
target = loop ? pages.Count - 1 : 0;
ShowPage(target);
}
/// Перейти на следующую страницу.
public void NextPage()
{
if (pages.Count == 0) return;
int target = _currentPage + 1;
if (target >= pages.Count)
target = loop ? 0 : pages.Count - 1;
ShowPage(target);
}
/// Показать страницу по индексу.
public void ShowPage(int index)
{
if (pages.Count == 0) return;
index = Mathf.Clamp(index, 0, pages.Count - 1);
for (int i = 0; i < pages.Count; i++)
{
if (pages[i] != null)
pages[i].SetActive(i == index);
}
_currentPage = index;
UpdateIndicator();
OnPageChanged?.Invoke(_currentPage);
}
// ───────────────────────── UI Update ─────────────────────────
private void UpdateIndicator()
{
if (pageIndicatorText != null)
{
pageIndicatorText.text = string.Format(pageIndicatorFormat, _currentPage + 1, pages.Count);
}
if (dotsContainer != null)
{
for (int i = 0; i < dotsContainer.childCount; i++)
{
var graphic = dotsContainer.GetChild(i).GetComponent();
if (graphic != null)
graphic.color = i == _currentPage ? dotActiveColor : dotInactiveColor;
}
}
if (prevArrowImage != null)
{
prevArrowImage.gameObject.SetActive(loop || _currentPage > 0);
}
if (nextArrowImage != null)
{
nextArrowImage.gameObject.SetActive(loop || _currentPage < pages.Count - 1);
}
}
}
}