using System.Reflection;
using PowerEasy.WebFuture.DataMigrations.Foundation.Database;
using PowerEasy.WebFuture.DataMigrations.Foundation.Enum;
using PowerEasy.WebFuture.DataMigrations.Foundation.Log;
using PowerEasy.WebFuture.DataMigrations.Foundation.Provider;

namespace PowerEasy.WebFuture.DataMigrations.Foundation.MigrationProgramme
{
    /// <summary>
    /// 迁移方案基类。
    /// </summary>
    public class BaseMigrationProgramme : IMigrationProgramme
    {
        /// <summary>
        /// 源数据库提供者。
        /// </summary>
        private IDatabaseProvider sourceDatabaseProvider;

        /// <summary>
        /// 目标数据库提供者。
        /// </summary>
        private IDatabaseProvider targetDatabaseProvider;

        /// <summary>
        /// 迁移项目集合。
        /// </summary>
        private List<IMigrationItem> migrationItems;

        /// <summary>
        /// 迁移方案标识。
        /// </summary>
        private string migrationProgrammeIdentifier;

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

                return this.migrationProgrammeIdentifier;
            }

            set
            {
                this.migrationProgrammeIdentifier = value;
            }
        }

        /// <summary>
        /// 迁移方案名称。
        /// </summary>
        public string MigrationProgrammeName { get; set; }

        /// <summary>
        /// 源数据库类型。
        /// </summary>
        public DatabaseType SourceDataBaseType { get; set; }

        /// <summary>
        /// 源数据库服务器地址。
        /// </summary>
        public string SourceDataBaseServer { get; set; }

        /// <summary>
        /// 源数据库服务器端口。
        /// </summary>
        public string SourceDataBasePort { get; set; }

        /// <summary>
        /// 源数据库名称。
        /// </summary>
        public string SourceDataBaseName { get; set; }

        /// <summary>
        /// 源数据库用户名。
        /// </summary>
        public string SourceDataBaseUserName { get; set; }

        /// <summary>
        /// 源数据库密码。
        /// </summary>
        public string SourceDataBasePassword { get; set; }

        /// <summary>
        /// 目标据库类型。
        /// </summary>
        public DatabaseType TargetDataBaseType { get; set; }

        /// <summary>
        /// 目标数据库服务器地址。
        /// </summary>
        public string TargetDataBaseServer { get; set; }

        /// <summary>
        /// 目标数据库服务器端口。
        /// </summary>
        public string TargetDataBasePort { get; set; }

        /// <summary>
        /// 目标数据库名称。
        /// </summary>
        public string TargetDataBaseName { get; set; }

        /// <summary>
        /// 目标数据库用户名。
        /// </summary>
        public string TargetDataBaseUserName { get; set; }

        /// <summary>
        /// 目标数据库密码。
        /// </summary>
        public string TargetDataBasePassword { get; set; }

        /// <summary>
        /// 迁移操作集合。
        /// </summary>
        public List<MigrationAction> MigrationActions { get; set; }

        /// <summary>
        /// 迁移操作集合。
        /// </summary>
        public virtual List<IMigrationItem> MigrationItems
        {
            get
            {
                if (this.migrationItems == null)
                {
                    this.migrationItems = new List<IMigrationItem>();

                    // 获取当前程序集。
                    Assembly assembly = Assembly.GetExecutingAssembly();

                    // 获取所有继承IMigrationItem接口的类型。
                    var migrationItemTypes = assembly.GetTypes().Where(t => !t.IsAbstract && typeof(IMigrationItem).IsAssignableFrom(t) && t.IsClass);

                    foreach (var type in migrationItemTypes)
                    {
                        try
                        {
                            // 排除父类。
                            if (type.Name.StartsWith("Base"))
                            {
                                continue;
                            }

                            var instance = Activator.CreateInstance(type) as IMigrationItem;
                            if (instance != null && instance.MigrationProgrammeIdentifier == this.MigrationProgrammeIdentifier)
                            {
                                this.migrationItems.Add(instance);
                            }
                        }
                        catch (Exception ex)
                        {
                            LogHelper.WriteLog($"加载迁移方案项目异常，异常类型：{type.Name}，{ex.ToString()}");
                        }
                    }
                }

                return this.migrationItems;
            }

            set
            {
                this.migrationItems = value;
            }
        }

        /// <summary>
        /// 开始执行迁移方案。
        /// </summary>
        /// <param name="isCheckedIncremental">是否勾选增量迁移。</param>
        /// <returns>返回执行迁移是否成功。</returns>
        public virtual bool StartMigration(bool isCheckedIncremental)
        {
            var enableMigrationItemList = this.MigrationItems.OrderBy(x => x.Order);
            bool allMigrationsSuccessful = true;

            foreach (var enableMigrationItem in enableMigrationItemList.Where(x => x.Enable))
            {
                var status = enableMigrationItem.StartMigration(isCheckedIncremental);
                allMigrationsSuccessful = allMigrationsSuccessful && status;
            }

            return allMigrationsSuccessful;
        }

        /// <summary>
        /// 获取源数据库提供者。
        /// </summary>
        /// <returns>返回源数据库提供者。</returns>
        public virtual IDatabaseProvider GetSourceDatabaseProvider()
        {
            if (this.sourceDatabaseProvider == null)
            {
                var sourceDatabaseConnection = new DataBaseConnectionHelper();
                sourceDatabaseConnection.DatabaseType = this.SourceDataBaseType;
                sourceDatabaseConnection.ServerName = this.SourceDataBaseServer;
                sourceDatabaseConnection.Port = this.SourceDataBasePort;
                sourceDatabaseConnection.Database = this.SourceDataBaseName;
                sourceDatabaseConnection.UserName = this.SourceDataBaseUserName;
                sourceDatabaseConnection.Password = this.SourceDataBasePassword;
                this.sourceDatabaseProvider = sourceDatabaseConnection.CreateProvider();
            }

            return this.sourceDatabaseProvider;
        }

        /// <summary>
        /// 获取目标数据库提供者。
        /// </summary>
        /// <returns>返回目标数据库提供者。</returns>
        public virtual IDatabaseProvider GetTargetDatabaseProvider()
        {
            if (this.targetDatabaseProvider == null)
            {
                var targetDatabaseConnection = new DataBaseConnectionHelper();
                targetDatabaseConnection.DatabaseType = this.TargetDataBaseType;
                targetDatabaseConnection.ServerName = this.TargetDataBaseServer;
                targetDatabaseConnection.Port = this.TargetDataBasePort;
                targetDatabaseConnection.Database = this.TargetDataBaseName;
                targetDatabaseConnection.UserName = this.TargetDataBaseUserName;
                targetDatabaseConnection.Password = this.TargetDataBasePassword;
                this.targetDatabaseProvider = targetDatabaseConnection.CreateProvider();
            }

            return this.targetDatabaseProvider;
        }
    }
}
