// ---------------------------------------------------------------------------
// BT.Framework
// DataTable.cs — 불변 마스터 테이블 (키·행)
// ---------------------------------------------------------------------------
using System;
using System.Collections.Generic;

namespace BurningTimes.Core.Data
{
    /// <summary>
    /// 로드 완료 이후 내용이 변경되지 않는 키·행 매핑 스냅샷.
    /// </summary>
    /// <typeparam name="TKey">행 키 타입 (보통 int·string·enum).</typeparam>
    /// <typeparam name="TRow">행 타입. <see cref="IDataRow{TKey}"/> 를 구현해야 함.</typeparam>
    /// <remarks>
    /// <para>설계 문서 §3-3 (04_Tier1_3종_상호작용_설계_v1.md). 기존 <c>MasterTableBase</c> 를 본 클래스로 재설계.</para>
    /// <para>계약:</para>
    /// <list type="bullet">
    ///   <item><description>생성 후 <see cref="Rows"/> 내용·길이는 변경되지 않는다 (불변 스냅샷).</description></item>
    ///   <item><description>동일 키가 중복 등장하면 <see cref="ArgumentException"/>.</description></item>
    ///   <item><description>런타임 쓰기가 필요하면 <see cref="BurningTimes.Core.Container.ObservableList{T}"/> 사용 (Container 모듈과 역할 분리).</description></item>
    /// </list>
    /// </remarks>
    public class DataTable<TKey, TRow> where TRow : IDataRow<TKey>
    {
        private readonly TRow[] _rows;
        private readonly Dictionary<TKey, TRow> _byKey;

        /// <summary>행의 읽기 전용 뷰 (원본 순서 보존).</summary>
        public IReadOnlyList<TRow> Rows => _rows;

        /// <summary>행 개수.</summary>
        public int Count => _rows.Length;

        /// <summary>
        /// 주어진 행 집합으로 테이블을 생성한다. 행 순서는 입력 순서를 보존한다.
        /// </summary>
        /// <exception cref="ArgumentNullException"><paramref name="rows"/> 가 null.</exception>
        /// <exception cref="ArgumentException">중복 키가 감지됨.</exception>
        public DataTable(IEnumerable<TRow> rows)
        {
            if (rows == null) throw new ArgumentNullException(nameof(rows));
            var list = new List<TRow>();
            var map = new Dictionary<TKey, TRow>();
            foreach (var row in rows)
            {
                if (row == null) continue;
                TKey key = row.Key;
                if (map.ContainsKey(key))
                    throw new ArgumentException($"중복 키: {key}", nameof(rows));
                map.Add(key, row);
                list.Add(row);
            }
            _rows = list.ToArray();
            _byKey = map;
        }

        /// <summary>키에 해당하는 행을 반환한다.</summary>
        /// <exception cref="KeyNotFoundException">키 미등록.</exception>
        public TRow Get(TKey key)
        {
            if (!_byKey.TryGetValue(key, out var row))
                throw new KeyNotFoundException($"키 미등록: {key}");
            return row;
        }

        /// <summary>키에 해당하는 행을 안전하게 조회한다.</summary>
        public bool TryGet(TKey key, out TRow row) => _byKey.TryGetValue(key, out row);

        /// <summary>키 등록 여부.</summary>
        public bool Contains(TKey key) => _byKey.ContainsKey(key);
    }
}
