using Apewer.Internals;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;

using static Apewer.TextUtility;

namespace Apewer.Source
{

    /// <summary>System.Data.DataTable 装箱查询。</summary>
    public class Query : IQuery, IDisposable, IToJson
    {

        private bool _disposed = false;
        private bool _success = false;
        private string _message = null;
        private DataTable _table = null;
        private DataTable[] _tables = null;

        /// <summary>创建实例,默认状态为失败。</summary>
        public Query(bool success = false, string message = null)
        {
            _success = false;
            _message = message;
        }

        /// <summary>创建实例,Exception 为 NULL 时成功,非 NULL 时失败。</summary>
        public Query(Exception exception)
        {
            _success = exception == null;
            _message = RuntimeUtility.Message(exception);
        }

        /// <summary>创建实例,包装一个 DataTable 对象,数据表为 NULL 时失败,非 NULL 时成功。</summary>
        public Query(DataTable table)
        {
            _table = table;
            _success = table != null;
            _message = table == null ? "未获取有效的数据表。" : null;
        }

        /// <summary>创建实例,包装一个 DataTable 对象。</summary>
        public Query(DataTable table, bool success, string message = null)
        {
            _table = table;
            _success = success;
            _message = message;
        }

        /// <summary>创建实例,包装多个 DataTable 对象。</summary>
        public Query(DataTable[] tables, bool success = true, string message = null)
        {
            _tables = tables;
            _success = success;
            _message = message;
            if (tables != null && tables.Length > 0) _table = tables[0];
        }

        #region Property

        /// <summary>语句执行成功。</summary>
        public bool Success { get => _success; }

        /// <summary>消息。</summary>
        public string Message { get => _message; }

        /// <summary>所有结果表。</summary>
        public DataTable[] Tables { get => _tables; }

        /// <summary>获取默认结果表。如果设置默认结果表,会丢失设置前的所有结果表。</summary>
        public DataTable Table { get => _table; }

        /// <summary>默认表中的数据总行数。</summary>
        public int Rows { get => _table == null ? 0 : _table.Rows.Count; }

        /// <summary>默认表中的数据总列数。</summary>
        public int Columns { get => _table == null ? 0 : _table.Columns.Count; }

        #endregion

        #region Value

        /// <summary>获取默认表中第 0 行、第 0 列的单元格内容。</summary>
        public object Value()
        {
            if (_disposed) return null;
            return Value(0, 0);
        }

        /// <summary>获取默认表中指定行中第 0 列的内容。</summary>
        /// <param name="rowIndex">行索引,从 0 开始。</param>
        public object Value(int rowIndex)
        {
            if (_disposed) return null;
            return Value(rowIndex, 0);
        }

        /// <summary>获取默认表中第 0 行指定列的内容。</summary>
        /// <param name="columnName">列名称。</param>
        public object Value(string columnName)
        {
            if (_disposed) return null;
            return Value(0, columnName);
        }

        /// <summary>获取默认表中指定单元格的内容。</summary>
        /// <param name="rowIndex">行索引,从 0 开始。</param>
        /// <param name="columnIndex">列索引,从 0 开始。</param>
        public object Value(int rowIndex, int columnIndex)
        {
            if (_disposed) return null;
            if (_table != null)
            {
                if (rowIndex >= 0 && rowIndex < _table.Rows.Count)
                {
                    if (columnIndex >= 0 && columnIndex < _table.Columns.Count)
                    {
                        return _table.Rows[rowIndex][columnIndex];
                    }
                }
            }
            return null;
        }

        /// <summary>获取默认表中指定单元的内容。</summary>
        /// <param name="rowIndex">行索引,从 0 开始。</param>
        /// <param name="columnName">列名称。</param>
        public object Value(int rowIndex, string columnName)
        {
            if (_disposed) return null;
            if ((Table != null) && !string.IsNullOrEmpty(columnName))
            {
                if ((rowIndex < Table.Rows.Count) && (rowIndex >= 0))
                {
                    try { return Table.Rows[rowIndex][columnName]; }
                    catch { }
                }
            }
            return null;
        }

        /// <summary>搜索默认表。</summary>
        /// <param name="conditionColumn">搜索条件:列名。</param>
        /// <param name="conditionValue">搜索条件:列值。</param>
        /// <param name="resultColumn">搜索结果。</param>
        public object Value(string conditionColumn, string conditionValue, string resultColumn)
        {
            if (_disposed) return null;
            if ((Table != null) && (!string.IsNullOrEmpty(conditionColumn)) && (conditionValue != null) && (!string.IsNullOrEmpty(resultColumn)))
            {
                for (int i = 0; i < Table.Rows.Count; i++)
                {
                    try
                    {
                        if (Table.Rows[i][conditionColumn].ToString() == conditionValue) return Table.Rows[i][resultColumn];
                    }
                    catch { }
                }
            }
            return null;
        }

        /// <summary>搜索默认表。</summary>
        /// <param name="conditionColumn">搜索条件:列名。</param>
        /// <param name="conditionValue">搜索条件:列值。</param>
        /// <param name="resultColumn">搜索结果的列名。</param>
        public object Value(int conditionColumn, string conditionValue, int resultColumn)
        {
            if (_disposed) return null;
            if ((Table != null) && (conditionColumn >= 0) && (conditionValue != null) && (resultColumn >= 0))
            {
                if ((conditionColumn < Table.Columns.Count) && (resultColumn < Table.Columns.Count))
                {
                    for (int i = 0; i < Table.Rows.Count; i++)
                    {
                        try
                        {
                            if (Table.Rows[i][conditionColumn].ToString() == conditionValue) return Table.Rows[i][resultColumn];
                        }
                        catch { }
                    }
                }
            }
            return null;
        }

        #endregion

        #region Method

        /// <summary>搜索默认表。</summary>
        /// <param name="conditionColumn">搜索条件:列名。</param>
        /// <param name="conditionValue">搜索条件:列值。</param>
        /// <param name="resultColumn">搜索结果。</param>
        public string Text(int conditionColumn, string conditionValue, int resultColumn)
        {
            var value = Value(conditionColumn, conditionValue, resultColumn);
            return Text(value);
        }

        /// <summary>释放系统资源。</summary>
        public virtual void Dispose()
        {
            if (_disposed) return;
            if (_tables != null)
            {
                foreach (var table in _tables) RuntimeUtility.Dispose(table);
                _tables = null;
            }
            RuntimeUtility.Dispose(_table);
            _table = null;
            _tables = null;
            _disposed = true;
            // GC.SuppressFinalize(this);
        }

        /// <summary>当不指定格式化程序时,自动根据类型选择预置的格式化程序。</summary>
        private static Func<object, T> GetValueFormatter<T>()
        {
            var type = typeof(T);
            if (type.Equals(typeof(string))) return TextFormatter<T>;
            else return ForceFormatter<T>;
        }

        /// <summary>获取指定列的所有值,无效值不加入结果。</summary>
        public T[] ReadColumn<T>(int column = 0, Func<object, T> formatter = null) => OrmHelper.Column(this, (r) => (formatter ?? GetValueFormatter<T>()).Invoke(Value(r, column)));

        /// <summary>获取指定列的所有值,无效值不加入结果。</summary>
        /// <exception cref="ArgumentNullException"></exception>
        public T[] ReadColumn<T>(string column, Func<object, T> formatter = null) => OrmHelper.Column(this, (r) => (formatter ?? GetValueFormatter<T>()).Invoke(Value(r, column)));

        /// <summary>获取指定列的所有值,无效值不加入结果。</summary>
        public string[] ReadColumn(int column = 0) => OrmHelper.Column(this, (r) => this.Text(r, column));

        /// <summary>获取指定列的所有值,无效值不加入结果。</summary>
        /// <exception cref="ArgumentNullException"></exception>
        public string[] ReadColumn(string column) => OrmHelper.Column(this, (r) => this.Text(r, column));

        #endregion

        #region IToJson

        /// <summary>转换为 Json 对象。</summary>
        public Json ToJson()
        {
            var columns = Json.NewArray();
            var rows = Json.NewArray();

            var table = _table;
            if (!_disposed && table != null)
            {
                var columnsCount = _table.Columns.Count;
                for (var c = 0; c < columnsCount; c++)
                {
                    var dc = table.Columns[c];
                    var column = Json.NewObject();
                    column.SetProperty("name", dc.ColumnName);
                    column.SetProperty("type", dc.DataType.FullName);
                    columns.AddItem(column);
                }

                var rowsCount = table.Rows.Count;
                for (var r = 0; r < _table.Rows.Count; r++)
                {
                    var row = Json.NewArray();
                    for (var c = 0; c < columnsCount; c++)
                    {
                        var v = Value(r, c);
                        if (v == null) row.AddItem();
                        else if (v.Equals(DBNull.Value)) row.AddItem();
                        else if (v is byte vByte) row.AddItem(vByte);
                        else if (v is short vInt16) row.AddItem(vInt16);
                        else if (v is int vInt32) row.AddItem(vInt32);
                        else if (v is long vInt64) row.AddItem(vInt64);
                        else if (v is float vSingle) row.AddItem(vSingle);
                        else if (v is double vDouble) row.AddItem(vDouble);
                        else if (v is decimal vDecimal) row.AddItem(vDecimal);
                        else if (v is bool vBoolean) row.AddItem(vBoolean);
                        else if (v is byte[] vBytes) row.AddItem(vBytes.Base64());
                        else if (v is DateTime vDateTime) row.AddItem(vDateTime.Lucid());
                        else row.AddItem(v.ToString());
                    }
                    rows.AddItem(row);
                }
            }

            var jsonObject = Json.NewObject();
            jsonObject.SetProperty("success", _success);
            jsonObject.SetProperty("message", _message);
            jsonObject.SetProperty("columns", columns);
            jsonObject.SetProperty("rows", rows);
            return jsonObject;
        }

        #endregion

        #region Static

        private static T ForceFormatter<T>(object input) => (T)input;

        private static T TextFormatter<T>(object input) => (T)(Text(input) as object);

        private static ObjectDisposedException DisposedException { get { return new ObjectDisposedException(typeof(Query).FullName); } }

        /// <summary>简单查询:取结果中第 0 列所有单元格的文本形式,可指定查询后关闭服务器连接,返回结果中不包含无效文本。</summary>
        public static string[] SimpleColumn(IDbClientAdo database, string statement, bool dispose = false)
        {
            if (database == null) return new string[0];
            var ab = new ArrayBuilder<string>();
            using (var query = database.Query(statement))
            {
                var rows = query.Rows;
                if (rows > 0)
                {
                    var added = 0;
                    for (int i = 0; i < rows; i++)
                    {
                        var cell = Trim(query.Text(i));
                        if (string.IsNullOrEmpty(cell)) continue;
                        ab.Add(cell);
                        added++;
                    }
                }
            }
            if (dispose) RuntimeUtility.Dispose(database);
            return ab.Export();
        }

        /// <summary>简单查询:取结果中第 0 行、第 0 列单元格中的文本,可指定查询后关闭服务器连接。</summary>
        public static string SimpleCell(IDbClientAdo database, string statement, bool dispose = false)
        {
            if (database == null) return "";
            var query = database.Query(statement);
            var cell = Trim(Query.Text(query.Value()));
            query.Dispose();
            if (dispose) RuntimeUtility.Dispose(database);
            return cell;
        }

        #endregion

        #region Extension

        internal static string Text(object value)
        {
            var result = Constant.EmptyString;
            if (value != null)
            {
                if (!value.Equals(DBNull.Value))
                {
                    try
                    {
                        result = value.ToString();
                    }
                    finally { }
                }
            }
            return result;
        }

        internal static Class<DateTime> DateTime(object value)
        {
            if (value == null) return null;
            if (value is DateTime) return null;
            DateTime result;
            var parsed = System.DateTime.TryParse(value.ToString(), out result);
            return parsed ? new Class<DateTime>(result) : null;
        }

        #endregion

    }

}