// ---------------------------------------------------------------------------
// BT.Framework
// DataTableLoader.cs — CSV·JSON 텍스트에서 DataTable 구축 헬퍼
// ---------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace BurningTimes.Core.Data
{
    /// <summary>
    /// 텍스트 원본(CSV·JSON)으로부터 <see cref="DataTable{TKey, TRow}"/> 를 구축하는 정적 헬퍼.
    /// </summary>
    /// <remarks>
    /// <para>설계 문서 §3-3·§6-5·§6-6. Tier 1 외부 의존성 최소 원칙에 따라:</para>
    /// <list type="bullet">
    ///   <item><description>CSV: 쉼표·따옴표 이스케이프·줄바꿈을 처리하는 최소 자체 파서.</description></item>
    ///   <item><description>JSON: Unity <see cref="JsonUtility"/> 기반. Dictionary·polymorphism 미지원 — 고급 케이스는 호출자가 자체 파싱.</description></item>
    /// </list>
    /// </remarks>
    public static class DataTableLoader
    {
        // -----------------------------------------------------------------
        // CSV
        // -----------------------------------------------------------------

        /// <summary>
        /// CSV 텍스트를 파싱하여 <see cref="DataTable{TKey, TRow}"/> 를 생성한다.
        /// </summary>
        /// <typeparam name="TKey">행 키 타입.</typeparam>
        /// <typeparam name="TRow">행 타입 (<see cref="IDataRow{TKey}"/> 구현).</typeparam>
        /// <param name="csvText">원본 텍스트.</param>
        /// <param name="rowFactory">컬럼 배열 → 행 인스턴스 변환기.</param>
        /// <param name="skipHeader">첫 줄을 헤더로 간주하여 건너뛸지 여부. 기본 true.</param>
        public static DataTable<TKey, TRow> FromCsv<TKey, TRow>(
            string csvText,
            Func<string[], TRow> rowFactory,
            bool skipHeader = true)
            where TRow : IDataRow<TKey>
        {
            if (csvText == null) throw new ArgumentNullException(nameof(csvText));
            if (rowFactory == null) throw new ArgumentNullException(nameof(rowFactory));

            var rows = new List<TRow>();
            var lines = ParseCsv(csvText);
            int start = skipHeader && lines.Count > 0 ? 1 : 0;
            for (int i = start; i < lines.Count; i++)
            {
                string[] cols = lines[i];
                if (IsEmptyRow(cols)) continue;
                TRow row = rowFactory(cols);
                if (row != null) rows.Add(row);
            }
            return new DataTable<TKey, TRow>(rows);
        }

        private static bool IsEmptyRow(string[] cols)
        {
            if (cols == null || cols.Length == 0) return true;
            for (int i = 0; i < cols.Length; i++)
            {
                if (!string.IsNullOrEmpty(cols[i])) return false;
            }
            return true;
        }

        /// <summary>
        /// CSV 텍스트를 행·컬럼 2차원 리스트로 파싱 (RFC 4180 준수 최소 구현).
        /// </summary>
        /// <remarks>쉼표·따옴표·따옴표 내 줄바꿈·연속 따옴표(<c>""</c> → <c>"</c>) 처리.</remarks>
        public static List<string[]> ParseCsv(string csvText)
        {
            var result = new List<string[]>();
            if (string.IsNullOrEmpty(csvText)) return result;

            var currentRow = new List<string>();
            var field = new StringBuilder();
            bool inQuotes = false;
            int len = csvText.Length;

            for (int i = 0; i < len; i++)
            {
                char c = csvText[i];
                if (inQuotes)
                {
                    if (c == '"')
                    {
                        if (i + 1 < len && csvText[i + 1] == '"')
                        {
                            field.Append('"');
                            i++;
                        }
                        else
                        {
                            inQuotes = false;
                        }
                    }
                    else
                    {
                        field.Append(c);
                    }
                }
                else
                {
                    if (c == '"')
                    {
                        inQuotes = true;
                    }
                    else if (c == ',')
                    {
                        currentRow.Add(field.ToString());
                        field.Length = 0;
                    }
                    else if (c == '\r')
                    {
                        // \r\n 또는 단독 \r 모두 줄 끝으로 취급
                        if (i + 1 < len && csvText[i + 1] == '\n') i++;
                        currentRow.Add(field.ToString());
                        field.Length = 0;
                        result.Add(currentRow.ToArray());
                        currentRow.Clear();
                    }
                    else if (c == '\n')
                    {
                        currentRow.Add(field.ToString());
                        field.Length = 0;
                        result.Add(currentRow.ToArray());
                        currentRow.Clear();
                    }
                    else
                    {
                        field.Append(c);
                    }
                }
            }

            // 마지막 필드·행 flush
            if (field.Length > 0 || currentRow.Count > 0)
            {
                currentRow.Add(field.ToString());
                result.Add(currentRow.ToArray());
            }

            return result;
        }

        // -----------------------------------------------------------------
        // JSON (Unity JsonUtility)
        // -----------------------------------------------------------------

        /// <summary>
        /// JSON 배열 래퍼 텍스트(<c>{"rows":[...]}</c>) 를 파싱하여 <see cref="DataTable{TKey, TRow}"/> 를 생성한다.
        /// </summary>
        /// <remarks>
        /// <para>Unity <see cref="JsonUtility"/> 는 최상위 배열을 직접 역직렬화하지 못하므로,
        /// <typeparamref name="TRowWrapper"/> 안에 공개 <c>List&lt;TRow&gt; rows</c> 필드 또는
        /// <c>TRow[] rows</c> 필드를 두고 감싸는 방식을 사용한다. 래퍼는 <see cref="RowListWrapper{TRow}"/> 를
        /// 직접 쓰거나, 호출자가 custom class 로 만들어 <paramref name="extractRows"/> 를 제공한다.</para>
        /// <para>고급 케이스(Dictionary 키·polymorphism)는 호출자가 자체 파싱 후 <see cref="DataTable{TKey, TRow}"/>
        /// 생성자에 직접 전달.</para>
        /// </remarks>
        /// <typeparam name="TKey">행 키 타입.</typeparam>
        /// <typeparam name="TRow">행 타입.</typeparam>
        /// <typeparam name="TRowWrapper">JSON 루트 래퍼 클래스 (반드시 <see cref="Serializable"/>).</typeparam>
        /// <param name="jsonText">원본 JSON.</param>
        /// <param name="extractRows">래퍼에서 행 목록을 꺼내는 함수.</param>
        public static DataTable<TKey, TRow> FromJson<TKey, TRow, TRowWrapper>(
            string jsonText,
            Func<TRowWrapper, IEnumerable<TRow>> extractRows)
            where TRow : IDataRow<TKey>
            where TRowWrapper : class
        {
            if (jsonText == null) throw new ArgumentNullException(nameof(jsonText));
            if (extractRows == null) throw new ArgumentNullException(nameof(extractRows));
            TRowWrapper wrapper = JsonUtility.FromJson<TRowWrapper>(jsonText);
            if (wrapper == null) return new DataTable<TKey, TRow>(new List<TRow>());
            var rows = extractRows(wrapper);
            return new DataTable<TKey, TRow>(rows ?? new List<TRow>());
        }
    }

    /// <summary>
    /// <see cref="DataTableLoader.FromJson{TKey, TRow, TRowWrapper}"/> 사용 시 기본 래퍼.
    /// </summary>
    /// <remarks>JSON 예: <c>{"rows":[{...},{...}]}</c>.</remarks>
    [Serializable]
    public class RowListWrapper<TRow>
    {
        public List<TRow> rows;
    }
}
