using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace PortProxyGUI.Data
{
    public class ApplicationDbMigrationUtil
    {
        public ApplicationDbScope DbScope { get; private set; }

        public ApplicationDbMigrationUtil(ApplicationDbScope context)
        {
            DbScope = context;
            EnsureHistoryTable();
            EnsureUpdateVersion();
        }

        public void EnsureHistoryTable()
        {
            if (!DbScope.SqlQuery($"SELECT * FROM sqlite_master WHERE type = 'table' AND name = '__history';").Any())
            {
                DbScope.UnsafeSql(@"CREATE TABLE __history ( MigrationId text PRIMARY KEY, ProductVersion text);");
                DbScope.UnsafeSql($"INSERT INTO __history (MigrationId, ProductVersion) VALUES ('000000000000', '0.0');");
            }
        }

        public void EnsureUpdateVersion()
        {
            var migration = GetLastMigration();
            var assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version;

            if (new Version(migration.ProductVersion) > assemblyVersion)
            {
                if (MessageBox.Show(@"The current software version cannot use the configuration.

You need to use a newer version of PortProxyGUI.

Would you like to download it now?", "Upgrade", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                {
                    Process.Start("explorer.exe", "https://github.com/zmjack/PortProxyGUI/releases");
                }

                Environment.Exit(0);
            }
        }

        public Migration GetLastMigration()
        {
            return DbScope.SqlQuery<Migration>($"SELECT * FROM __history ORDER BY MigrationId DESC LIMIT 1;").First();
        }

        public void MigrateToLast()
        {
            var migration = GetLastMigration();
            var migrationId = migration.MigrationId;
            var pendingMigrations = migrationId != "000000000000"
                ? History.SkipWhile(pair => pair.Key.MigrationId != migrationId).Skip(1)
                : History;

            foreach (var pendingMigration in pendingMigrations)
            {
                foreach (var sql in pendingMigration.Value)
                {
                    DbScope.UnsafeSql(sql);
                }
                DbScope.Sql($"INSERT INTO __history (MigrationId, ProductVersion) VALUES ({pendingMigration.Key.MigrationId}, {pendingMigration.Key.ProductVersion});");
            }
        }

        public Dictionary<MigrationKey, string[]> History = new Dictionary<MigrationKey, string[]>
        {
            [new MigrationKey { MigrationId = "202103021542", ProductVersion = "1.1.0" }] = new[]
            {
                @"CREATE TABLE rules
(
    Id text PRIMARY KEY,
    Type text,
    ListenOn text,
    ListenPort integer,
    ConnectTo text,
    ConnectPort integer
);",
                "CREATE UNIQUE INDEX IX_Rules_Type_ListenOn_ListenPort ON Rules(Type, ListenOn, ListenPort);",
            },

            [new MigrationKey { MigrationId = "202201172103", ProductVersion = "1.2.0" }] = new[]
            {
                "ALTER TABLE rules ADD Note text;",
                "ALTER TABLE rules ADD `Group` text;",
            },

            [new MigrationKey { MigrationId = "202202221635", ProductVersion = "1.3.0" }] = new[]
            {
                "ALTER TABLE rules RENAME TO rulesOld;",
                "DROP INDEX IX_Rules_Type_ListenOn_ListenPort;",

                @"CREATE TABLE rules (
	Id text PRIMARY KEY,
	Type text,
	ListenOn text,
	ListenPort integer,
	ConnectTo text,
	ConnectPort integer,
	Comment text,
	`Group` text 
);",
                "CREATE UNIQUE INDEX IX_Rules_Type_ListenOn_ListenPort ON Rules ( Type, ListenOn, ListenPort );",

                "INSERT INTO rules SELECT Id, Type, ListenOn, ListenPort, ConnectTo, ConnectPort, Note, `Group` FROM rulesOld;",
                "DROP TABLE rulesOld;",
            },
        };
    }
}