using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using UnityEngine.Networking;
using UnityEngine.XR;
using XRTool.Util;

namespace PublicTools.XMLDataBase
{
    public enum DataType
    {
        /// <summary>
        /// xml的方式存储
        /// </summary>
        Xml = 0,
        /// <summary>
        /// json文本的方式存储
        /// </summary>
        Json = 1,
        /// <summary>
        /// sqlite
        /// </summary>
        SqlLite = 2,
        /// <summary>
        /// 文本的方式存储
        /// </summary>
        Txt = 3,
        /// <summary>
        /// mysql读写
        /// </summary>
        MySql = 4,
        /// <summary>
        /// 预留扩展
        /// </summary>
        Other = 5
    }
    /// <summary>
    /// 数据库的管理类
    /// 注意同时只能操作一个数据库文件，当传入新的路径时，老的文件连接都将被关闭
    /// </summary>
    public class XSql : Singleton<XSql>
    {
        private Dictionary<string, string> sqlList = new Dictionary<string, string>();

        /// <summary>
        /// 缓存表格处理对象
        /// </summary>
        private Dictionary<string, TableInterface> tableDic = new Dictionary<string, TableInterface>();
        private string sqlPath;
        /// <summary>
        /// 当前正在处理的数据库文件路径
        /// </summary>
        public string SqlPath { get => sqlPath; set => sqlPath = value; }

        /// <summary>
        /// 打开数据库
        /// 即创建文件夹，开启对应的文件的读取流
        /// 同时仅能操作一个文件夹
        /// </summary>
        /// <param name="sqlPath">绝对路径</param>
        public bool Open(string sqlPath, bool isforceCreate = false)
        {
            if (!string.IsNullOrEmpty(sqlPath) && SqlPath == sqlPath)
            {
                return true;
            }
            try
            {
                if (isforceCreate && !Directory.Exists(sqlPath))
                {
                    Directory.CreateDirectory(sqlPath);
                }
                if (Directory.Exists(sqlPath))
                {
                    this.SqlPath = sqlPath;
                    return true;
                }
            }
            catch (Exception ex)
            {
                UnityLog.LogException(ex);
                UnityLog.LogError(ex.ToString());
            }
            return false;
        }
        /// <summary>
        /// 关闭数据库
        /// 即关闭此文件夹的所有文件读取流
        /// </summary>
        /// <param name="sqlPath"></param>
        public void Close()
        {
            foreach (var item in tableDic)
            {
                item.Value.Close();
            }
            tableDic.Clear();
        }
        public TableInterface OpenTable(string tableName, DataType dataType, bool forceCreate = false)
        {
            string suffix = ".xml";
            if (dataType == DataType.Xml)
            {
                suffix = ".xml";
            }

            else if (dataType == DataType.Json)
            {
                suffix = ".json";
            }

            return OpenTable(tableName, suffix, forceCreate);
        }
        /// <summary>
        /// 打开本地表格
        /// 打开对应的文件流，文件流存在时可能为空
        /// 操作表格的情况：不存在文件，存在但是字节流为空，字节流不为空
        /// 字节流为空时如何处理？
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="forceCreate">强制创建，文件为空时创建我呢见</param>
        /// <param name="suffix">文件后缀名</param>
        public TableInterface OpenTable(string tableName, string suffix = ".xml", bool forceCreate = false)
        {
            return OpenTable(SqlPath, tableName, suffix, forceCreate);
        }
        /// <summary>
        /// 打开本地表格
        /// 打开对应的文件流，文件流存在时可能为空
        /// 操作表格的情况：不存在文件，存在但是字节流为空，字节流不为空
        /// 字节流为空时如何处理？
        /// 注意安卓下StreamPath下无法使用File类读取！会报告异常
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="forceCreate">强制创建，文件为空时创建我呢见</param>
        /// <param name="suffix">文件后缀名</param>
        public TableInterface OpenTable(string sqlPath, string tableName, string suffix = ".xml", bool forceCreate = false)
        {
            if (!Open(sqlPath, forceCreate))
            {
                return null;
            }
            string unExtenName = Path.GetFileNameWithoutExtension(tableName);

            if (tableDic.ContainsKey(unExtenName))
            {
                return tableDic[unExtenName];
            }
            ///文件后缀,如果table已有后缀不添加后缀，若无后缀名，则添加指定的后缀名
            if (string.IsNullOrEmpty(Path.GetExtension(tableName)))
            {
                tableName += suffix;
            }
            string path = Path.Combine(sqlPath, tableName);
            try
            {
                bool isCreateNewTable = false;
                ///目标文件不存在，强制创建
                if (forceCreate && !File.Exists(path))
                {
                    File.Create(path).Dispose();
                    isCreateNewTable = true;
                }
                ///文件存在，创建对应的对象
                if (File.Exists(path))
                {
                    TableInterface fs = new XTable(path);
                    tableDic.Add(unExtenName, fs);
                    if (isCreateNewTable)
                    {
                        fs.Create(tableName);
                        fs.Save();
                    }
                    return fs;
                }
            }
            catch (Exception ex)
            {
                ///IO异常处理
                UnityEngine.Debug.LogException(ex);
                UnityLog.LogError(ex.ToString());
            }
            return null;
        }
        /// <summary>
        /// 关闭本地表操作
        /// </summary>
        /// <param name="tableName"></param>
        public void CloseTable(string tableName)
        {
            string unExtenName = Path.GetFileNameWithoutExtension(tableName);
            if (tableDic.ContainsKey(unExtenName))
            {
                tableDic[unExtenName].Close();
                tableDic.Remove(unExtenName);
            }
        }


        /// <summary>
        /// 新建一个表格
        /// </summary>
        /// <param name="tableName"></param>
        public bool CreateTable(string tableName, DataType dataType)
        {
            string suffix = ".xml";
            if (dataType == DataType.Xml)
            {
                suffix = ".xml";
            }

            else if (dataType == DataType.Json)
            {
                suffix = ".json";
            }
            return CreateTable(tableName, suffix);
        }
        /// <summary>
        /// 新建一个表格
        /// </summary>
        /// <param name="tableName"></param>
        public bool CreateTable(string tableName, string suffix = ".xml")
        {
            if (string.IsNullOrEmpty(Path.GetExtension(tableName)))
            {
                tableName += suffix;
            }
            TableInterface table = new XTable();
            return table.Create(tableName);
        }


        /// <summary>
        /// 读取远程的表格数据信息
        /// 或者在只读文件夹下读取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data">数据</param>
        /// <param name="type">数据类型，可能是.xml或者json文本0代表xml文本</param>
        /// <returns></returns>
        public List<T> ReadServerData<T>(byte[] data, int type = 0)
        {
            TableInterface table = new XTable(type);
            List<T> list = table.FindAllData<T>(data);
            table.Close();
            table = null;
            return list;
        }
        /// <summary>
        /// 读取远程的表格数据信息
        /// 或者在只读文件夹下读取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data">数据</param>
        /// <param name="type">数据类型，可能是.xml或者json文本0代表xml文本</param>
        /// <returns></returns>
        public List<T> ReadServerData<T>(string data, int type = 0)
        {
            TableInterface table = new XTable(type);
            List<T> list = table.FindAllData<T>(data);
            table.Close();
            table = null;
            return list;
        }
        public IEnumerator ReadServerData<T>(string url, Action<List<T>> action, int type = 0)
        {
            yield return UnityUtil.RequestDownData(url, (string error, UnityWebRequest handler) =>
            {
                if (!string.IsNullOrEmpty(error))
                {
                    UnityLog.LogError(url + "Read Data Error" + error);
                    action?.Invoke(null);
                }
                else
                {
                    action?.Invoke(ReadServerData<T>(handler.downloadHandler.data, type));
                }
            });
        }
    }
}