using System.Data;
using PowerEasy.WebFuture.DataMigrations.Foundation.Log;
using PowerEasy.WebFuture.DataMigrations.Foundation.MigrationProgramme;

namespace PowerEasy.WebFuture.DataMigrations.Foundation.Service
{
    /// <summary>
    /// 迁移项目内容模型基类。
    /// </summary>
    public abstract class BaseContentMoldDataMigrationItem : IMigrationItem
    {
        /// <summary>
        /// 构造函数。
        /// </summary>
        public BaseContentMoldDataMigrationItem()
        {
        }

        /// <summary>
        /// 模型名字。
        /// </summary>
        public abstract string ModelName { get; set; }

        /// <summary>
        /// 迁移项目的排序，用于执行和工具显示的顺序，从小到大排序。
        /// </summary>
        public abstract int Order { get; set; }

        /// <summary>
        /// 迁移项目名称。
        /// </summary>
        public abstract string MigrationItemName { get; set; }

        /// <summary>
        /// 目标数据库表名。
        /// </summary>
        public abstract string TargetDatabaseTableName { get; set; }

        /// <summary>
        /// 来源数据库表的主键名称。
        /// </summary>
        public abstract string SourcePrimaryKeyName { get; set; }

        /// <summary>
        /// 来源数据库表的节点名称。
        /// </summary>
        public abstract string SourceNodeIdName { get; set; }

        /// <summary>
        /// 上传目录。
        /// </summary>
        public abstract string UploadPath { get; set; }

        /// <summary>
        /// 目标站点id。
        /// </summary>
        public abstract int SiteId { get; set; }

        /// <summary>
        /// 迁移项目是否勾选。
        /// </summary>
        public bool Enable { get; set; }

        /// <summary>
        /// 来源数据库表数据。
        /// </summary>
        public DataTable SourceDataTable { get; set; }

        /// <summary>
        /// 使用设置赋值的NodeId（选择True，就使用手动赋值的NodeId，否则自动赋值NodeId）。
        /// </summary>
        public bool EnableUseNodeId { get; set; }

        /// <summary>
        /// 发改委特殊用。
        /// </summary>
        public int OldMoldId { get; set; }

        /// <summary>
        /// 迁移方案标识。
        /// </summary>
        /// <remarks>
        /// 迁移项目的标识需要与迁移方案标识相同。
        /// 如果迁移项目跟迁移方案命名空间相同时，可不指定标识，系统会将命名空间作为标识。
        /// </remarks>
        public string MigrationProgrammeIdentifier
        {
            get
            {
                if (string.IsNullOrEmpty(this.MigrationProgrammeIdentifierString))
                {
                    this.MigrationProgrammeIdentifierString = this.GetType().Namespace;
                }

                return this.MigrationProgrammeIdentifierString;
            }

            set
            {
                this.MigrationProgrammeIdentifierString = value;
            }
        }

        /// <summary>
        /// 迁移方案标识。
        /// </summary>
        private string MigrationProgrammeIdentifierString { get; set; }

        /// <summary>
        /// 开始执行迁移项目。
        /// </summary>
        /// <param name="isCheckedIncremental">是否勾选增量迁移。</param>
        /// <returns>返回迁移结果。</returns>
        public virtual bool StartMigration(bool isCheckedIncremental)
        {
            LogHelper.BackgroundWorker.ReportProgress(0, $"{this.MigrationItemName}开始。");
            var status = this.StartInsert(isCheckedIncremental);
            LogHelper.BackgroundWorker.ReportProgress(100, $"{this.MigrationItemName}结束。");
            return status;
        }

        /// <summary>
        /// 获取批量插入的数据表。
        /// </summary>
        /// <returns>返回数据表。</returns>
        public virtual DataTable GetInsertDataTable()
        {
            var targetDatabaseProvider = DatabaseService.GetTargetDatabaseProvider(this.MigrationProgrammeIdentifier);

            // 获取新库当前站点的节点数据。
            string nodeSql = targetDatabaseProvider.GetAllDataByTableNameAndSiteId("PE_ContentManage_Node", this.SiteId, "Left");
            var nodeDataTable = targetDatabaseProvider.ExecuteDataTable(nodeSql);

            // 获取新目标数据库对应迁移表的字段结构。
            var moldDataTable = new DataTable();
            var moldDataSql = targetDatabaseProvider.GetOneDataByTableName(this.TargetDatabaseTableName);
            moldDataTable = targetDatabaseProvider.ExecuteDataTable(moldDataSql);

            // 构建需要迁移的数据表。
            var migrationDataTable = new DataTable();
            migrationDataTable.TableName = this.TargetDatabaseTableName;
            for (int i = 0; i < moldDataTable.Columns.Count; i++)
            {
                migrationDataTable.Columns.Add(moldDataTable.Columns[i].ColumnName, moldDataTable.Columns[i].DataType);
            }

            // 获取新库表最大的Id。
            string targetLastMoldSql = targetDatabaseProvider.GetOneDataByTableNameAndOrder(this.TargetDatabaseTableName, "ContentId");
            var targetLastMold = targetDatabaseProvider.ExecuteDataTable(targetLastMoldSql);
            int contentId = 0;
            if (targetLastMold.Rows.Count > 0)
            {
                contentId = Convert.ToInt32(targetLastMold.Rows[0]["ContentId"]);
            }

            foreach (DataRow moldRow in this.SourceDataTable.Rows)
            {
                // 下面进行数据库录入。
                DataRow newRow = migrationDataTable.NewRow();

                // 获取旧数据库和新数据库字段对应的行数据。
                var mold = this.MapFields(moldRow, newRow);

                // 主键Id需要手动控制自增，数据库中没有设置组件自增。
                contentId = contentId + 1;
                mold["ContentId"] = contentId;

                if (!this.EnableUseNodeId)
                {
                    string old_NodeId = moldRow[this.SourceNodeIdName].ToString();
                    var str = string.Empty;
                    if (this.OldMoldId != 0)
                    {
                        str = $"SourceNodeId='{old_NodeId + "_" + this.OldMoldId}'and MoldId='{this.OldMoldId}'";
                    }
                    else
                    {
                        str = $"SourceNodeId='{old_NodeId}'";
                    }

                    var dataRow = nodeDataTable.Select(str);
                    if (dataRow.Length > 0)
                    {
                        mold["NodeId"] = Convert.ToInt32(dataRow[0]["NodeId"]);
                    }
                    else
                    {
                        mold["NodeId"] = 1;
                    }
                }

                // 原样迁移的一二节点Id。
                var nodeId = Convert.ToInt32(mold["NodeId"].ToString());
                var rootNodeId = 0;
                var masterNodeId = 0;
                var dataRowNode = nodeDataTable.Select($"NodeId='{nodeId}'");
                if (dataRowNode.Length > 0)
                {
                    var depth = Convert.ToInt32(dataRowNode[0]["Depth"]);
                    var left = Convert.ToInt32(dataRowNode[0]["Left"]);
                    var right = Convert.ToInt32(dataRowNode[0]["Right"]);
                    if (depth == 0)
                    {
                        rootNodeId = Convert.ToInt32(dataRowNode[0]["NodeId"]);
                    }
                    else
                    {
                        var rmSql = targetDatabaseProvider.GetRootNodeIDAndMasterNodeID(this.SiteId, left, right);
                        DataTable node = targetDatabaseProvider.ExecuteDataTable(rmSql);
                        if (node.Rows.Count > 0)
                        {
                            var firstNode = node.Rows[0];
                            if (firstNode != null)
                            {
                                int.TryParse(firstNode["NodeId"].ToString(), out rootNodeId);
                            }

                            if (depth == 1)
                            {
                                if (dataRowNode[0] != null)
                                {
                                    int.TryParse(dataRowNode[0]["NodeId"].ToString(), out masterNodeId);
                                }
                            }
                            else
                            {
                                if (node.Rows.Count > 0 && node.Rows[1] != null)
                                {
                                    int.TryParse(node.Rows[1]["NodeId"].ToString(), out masterNodeId);
                                }
                            }
                        }
                    }
                }

                mold["RootNodeID"] = rootNodeId;
                mold["MasterNodeID"] = masterNodeId;

                migrationDataTable.Rows.Add(mold);
            }

            return migrationDataTable;
        }

        /// <summary>
        /// 获取来源要迁移的数据集合。
        /// </summary>
        /// <param name="newContentId">最新迁移的数据主键。</param>
        public abstract void LoadSourceDataTable(int newContentId);

        /// <summary>
        /// 字段映射。
        /// </summary>
        /// <param name="sourceDataRow">源数据表行数据。</param>
        /// <param name="targetDataRow">目标数据表行数据。</param>
        /// <returns>返回映射后的行数据。</returns>
        public abstract DataRow MapFields(DataRow sourceDataRow, DataRow targetDataRow);

        /// <summary>
        /// 开始插入公共方法。
        /// </summary>
        /// <param name="isCheckedIncremental">是否勾选增量迁移。</param>
        /// <returns>返回执行结果。</returns>
        public bool StartInsert(bool isCheckedIncremental)
        {
            LogHelper.StartWriteLogAndFormLogByAsyn(this.ModelName);
            var targetDatabaseProvider = DatabaseService.GetTargetDatabaseProvider(this.MigrationProgrammeIdentifier);
            var newContentId = 0;
            if (isCheckedIncremental)
            {
                string historyIdSql = targetDatabaseProvider.GetOneDataByTableNameAndOrder(this.TargetDatabaseTableName, "HistoryId");
                var historyId = targetDatabaseProvider.ExecuteDataTable(historyIdSql);
                if (historyId.Rows.Count > 0)
                {
                    newContentId = Convert.ToInt32(historyId.Rows[0]["HistoryId"]);
                }
            }

            var status = true;
            var allStatus = true;
            var count = 0;
            while (true)
            {
                // 获取当前旧站数据。
                this.LoadSourceDataTable(newContentId);
                if (this.SourceDataTable.Rows.Count == 0)
                {
                    break;
                }

                var dataTable = this.GetInsertDataTable();
                count = count + dataTable.Rows.Count;

                // 批量插入。
                status = targetDatabaseProvider.BatchInsert(dataTable);
                LogHelper.IngWriteLogAndFormLogByAsyn(this.ModelName, status, count);

                if (status == false)
                {
                    allStatus = false;
                }

                var lastRow = this.SourceDataTable.Rows[this.SourceDataTable.Rows.Count - 1];
                newContentId = int.Parse(lastRow[this.SourcePrimaryKeyName].ToString());
                this.SourceDataTable.Clear();
                dataTable.Clear();
            }

            LogHelper.FinishWriteLogAndFormLogByAsyn(this.ModelName, allStatus);
            return allStatus;
        }
    }
}
