using kmSqlReplicate.ClassObj;
using log4net;
using log4net.Config;
using Microsoft.Data.SqlClient;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using Newtonsoft.Json;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using Topshelf;

namespace kmSqlReplicate;

internal class Program
{
  internal static string AppPath = AppDomain.CurrentDomain.BaseDirectory.Trim();
  internal static string AppName = AppDomain.CurrentDomain.FriendlyName.Trim();
  internal static string MachineName = Environment.MachineName.Trim();
  internal static string ProgramVersion = string.Empty;
  internal static bool exitNow = false;

  static void Main(string[] args)
  {
    var logRepo = LogManager.GetRepository(Assembly.GetEntryAssembly());
    XmlConfigurator.Configure(logRepo, new FileInfo(Path.Combine(AppPath, "log4net.config")));
    GlobalContext.Properties["Application"] = AppName;

    SetProgramVersion();
    if (Debugger.IsAttached)
    {
      var obj = new ClsReplicateBase();
      obj.Go();
      //Test1();
    }
    else
    {
      var rc = HostFactory.Run(x =>
      {
        x.Service<ServiceMain>();
        x.EnableServiceRecovery(r => r.RestartService(TimeSpan.FromSeconds(15)));
        x.SetServiceName("kmSqlReplicate");
        x.StartAutomaticallyDelayed();
        x.SetDescription("Will handle replicating of tables in SQL between two servers.");
        x.UseLog4Net();
      });
    }
  }
  private static void SetProgramVersion()
  {
    string FullExecutableName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
    var fif = new FileInfo(FullExecutableName);

    ProgramVersion = string.Format("{0} ({1:d-MMM-yyyy})", FileVersionOf(FullExecutableName), fif.LastWriteTime);
  } //SetProgramVersion
  internal static Version FileVersionOf(string Filename)
  {
    Version rv;
    try
    {
      var myBuildInfo = FileVersionInfo.GetVersionInfo(Filename);
      string kmBuildVersion = "";

      kmBuildVersion = string.Format("{0}.{1}.{2}.{3}", myBuildInfo.ProductMajorPart, myBuildInfo.ProductMinorPart, myBuildInfo.ProductBuildPart, myBuildInfo.ProductPrivatePart);
      rv = new Version(kmBuildVersion);
    }
    catch
    {
      rv = new Version("1.0");
    }

    return rv;
  } //FileVersionOf

  internal static void Test1()
  {
    ScriptingOptions scrOptions1, scrOptions2, scrOptions3, scrOptions4;

    scrOptions1 = new ScriptingOptions()    // Drops first
    {
      Default = true,
      //NoIdentities = true,
      ScriptDrops = true,
      //ScriptOwner = true,
      //NoFileGroup = false,
      //NoIndexPartitioningSchemes = true,
      //NoTablePartitioningSchemes = true,
      ScriptForCreateDrop = true,
      DriAllConstraints = true,
      //DriDefaults = true,
      DriForeignKeys = true,
      IncludeIfNotExists = true,
      //EnforceScriptingOptions = true,
      //AllowSystemObjects = false,
      //Indexes = true,
      DriAllKeys = true,
      DriChecks = true,
      //FullTextIndexes = true,
      //Statistics = true,
      //Triggers = true,
      //WithDependencies = true,
      DriAll = true,
    };
    scrOptions2 = new ScriptingOptions()    // Then CREATE
    {
      Default = true,
      NoIdentities = false,
      ScriptDrops = false,
      ScriptOwner = false,
      NoFileGroup = false,
      NoIndexPartitioningSchemes = true,
      NoTablePartitioningSchemes = true,
      //ScriptForCreateDrop = true,
      //Statistics = true,
      //Triggers = true,
    };
    scrOptions3 = new ScriptingOptions()    // Get all keys and indexes
    {
      Default = false,
      DriPrimaryKey = true,
      Indexes = true,
      ScriptOwner = false,
      NoFileGroup = false,
      NoIndexPartitioningSchemes = true,
      NoTablePartitioningSchemes = true,
      ScriptForCreateDrop = true,
      FullTextIndexes = true,
      DriAll = true
    };
    scrOptions4 = new ScriptingOptions()    // Get the permissions
    {
      Default = false,
      Permissions = true
    };

    using (var cnSrc = new SqlConnection(string.Format("Server={0};Database={1};Integrated Security=SSPI;TrustServerCertificate=True;", "BigMac", "MyCarHQ")))
    {
      var scrOutput = new StringCollection();
      var txtSql = new StringBuilder();

      cnSrc.Open();

      Server S1 = new Server(new Microsoft.SqlServer.Management.Common.ServerConnection(cnSrc));
      Database D1 = S1.Databases["MyCarHQ"];
      Table T1 = D1.Tables["SourceFiles", "appt"];

      //foreach (var fk in T1.ForeignKeys)
      //  Console.WriteLine("DROP " + fk.ToString());

      var scr = new Scripter(S1) { Options = scrOptions1 };
      //scr.Options.IncludeIfNotExists = true;
      //scr.Options.ScriptSchema = true;
      //scr.Options.ScriptDrops = true;
      //Console.WriteLine (scr.EnumScript(new Urn[] { T1.Urn }).ToString());

      var dw = new DependencyWalker(S1);
      var dwTree = dw.DiscoverDependencies(new Urn[] { T1.Urn }, true);
      var ddd = dw.WalkDependencies(dwTree);

      foreach (var d in ddd)
      {
        foreach (var s in scr.EnumScript(new[] { d.Urn }))
        {
          Console.WriteLine(s);
        }
      }


      //foreach (string s in scr.EnumScript(new Urn[] { T1.Urn }))
      //  Console.WriteLine(s + "\n\n");

      Console.ReadLine();

      if (false)
      {
        txtSql.Append(string.Join("\n", T1.Script(scrOptions1).Cast<string>().ToArray()));
        txtSql.AppendLine("\nGO\n\n\n\n");
        txtSql.Append(string.Join("\n", T1.Script(scrOptions2).Cast<string>().ToArray()));
        txtSql.AppendLine("\nGO\n\n\n\n");
        txtSql.Append(string.Join("\n", T1.Script(scrOptions3).Cast<string>().ToArray()));
        txtSql.AppendLine("\nGO\n");

        Console.WriteLine(txtSql.ToString());
        Console.ReadLine();
      }
    }
  }
}
