using SharpChat.Config;
using SharpChat.EventStorage;
using SharpChat.Misuzu;
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;

namespace SharpChat {
    public class Program {
        public const string CONFIG = "sharpchat.cfg";

        public static void Main() {
            Console.WriteLine(@"   _____ __                     ________          __ ");
            Console.WriteLine(@"  / ___// /_  ____ __________  / ____/ /_  ____ _/ /_");
            Console.WriteLine(@"  \__ \/ __ \/ __ `/ ___/ __ \/ /   / __ \/ __ `/ __/");
            Console.WriteLine(@" ___/ / / / / /_/ / /  / /_/ / /___/ / / / /_/ / /_  ");
            Console.WriteLine(@"/____/_/ /_/\__,_/_/  / .___/\____/_/ /_/\__,_/\__/  ");
            /**/Console.Write(@"                     /__/");
            if(SharpInfo.IsDebugBuild) {
                Console.WriteLine();
                Console.Write(@"== ");
                Console.Write(SharpInfo.VersionString);
                Console.WriteLine(@" == DBG ==");
            } else
                Console.WriteLine(SharpInfo.VersionStringShort.PadLeft(28, ' '));

            using ManualResetEvent mre = new(false);
            bool hasCancelled = false;

            void cancelKeyPressHandler(object? sender, ConsoleCancelEventArgs ev) {
                Console.CancelKeyPress -= cancelKeyPressHandler;
                hasCancelled = true;
                ev.Cancel = true;
                mre.Set();
            };
            Console.CancelKeyPress += cancelKeyPressHandler;

            if(hasCancelled) return;

            string configFile = CONFIG;

            // If the config file doesn't exist and we're using the default path, run the converter
            if(!File.Exists(configFile) && configFile == CONFIG)
                ConvertConfiguration();

            using StreamConfig config = StreamConfig.FromPath(configFile);

            if(hasCancelled) return;

            using HttpClient httpClient = new(new HttpClientHandler() {
                UseProxy = false,
            });
            httpClient.DefaultRequestHeaders.Add("User-Agent", SharpInfo.ProgramName);

            if(hasCancelled) return;

            MisuzuClient msz = new(httpClient, config.ScopeTo("msz"));

            if(hasCancelled) return;

            IEventStorage evtStore;
            if(string.IsNullOrWhiteSpace(config.SafeReadValue("mariadb:host", string.Empty))) {
                evtStore = new VirtualEventStorage();
            } else {
                MariaDBEventStorage mdbes = new(MariaDBEventStorage.BuildConnString(config.ScopeTo("mariadb")));
                evtStore = mdbes;
                mdbes.RunMigrations();
            }

            if(hasCancelled) return;

            using SockChatServer scs = new(httpClient, msz, evtStore, config.ScopeTo("chat"));
            scs.Listen(mre);

            mre.WaitOne();
        }

        private static void ConvertConfiguration() {
            using Stream s = new FileStream(CONFIG, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
            s.SetLength(0);
            s.Flush();

            using StreamWriter sw = new(s, new UTF8Encoding(false));
            sw.WriteLine("# and ; can be used at the start of a line for comments.");
            sw.WriteLine();

            sw.WriteLine("# General Configuration");
            sw.WriteLine($"#chat:port            {SockChatServer.DEFAULT_PORT}");
            sw.WriteLine($"#chat:msgMaxLength    {SockChatServer.DEFAULT_MSG_LENGTH_MAX}");
            sw.WriteLine($"#chat:connMaxCount    {SockChatServer.DEFAULT_MAX_CONNECTIONS}");
            sw.WriteLine($"#chat:floodKickLength {SockChatServer.DEFAULT_FLOOD_KICK_LENGTH}");


            sw.WriteLine();
            sw.WriteLine("# Channels");
            sw.WriteLine("chat:channels lounge staff");
            sw.WriteLine();

            sw.WriteLine("# Lounge channel settings");
            sw.WriteLine("chat:channels:lounge:name Lounge");
            sw.WriteLine("chat:channels:lounge:autoJoin true");
            sw.WriteLine();

            sw.WriteLine("# Staff channel settings");
            sw.WriteLine("chat:channels:staff:name Staff");
            sw.WriteLine("chat:channels:staff:minRank 5");


            const string msz_secret = "login_key.txt";
            const string msz_url = "msz_url.txt";

            sw.WriteLine();
            sw.WriteLine("# Misuzu integration settings");
            if(File.Exists(msz_secret))
                sw.WriteLine(string.Format("msz:secret {0}", File.ReadAllText(msz_secret).Trim()));
            else
                sw.WriteLine("#msz:secret woomy");
            if(File.Exists(msz_url))
                sw.WriteLine(string.Format("msz:url    {0}/_sockchat", File.ReadAllText(msz_url).Trim()));
            else
                sw.WriteLine("#msz:url    https://flashii.net/_sockchat");


            const string mdb_config = @"mariadb.txt";
            string[] mdbCfg = File.Exists(mdb_config) ? File.ReadAllLines(mdb_config) : [];

            sw.WriteLine();
            sw.WriteLine("# MariaDB configuration");
            if(mdbCfg.Length > 0)
                sw.WriteLine($"mariadb:host {mdbCfg[0]}");
            else
                sw.WriteLine($"#mariadb:host <username>");
            if(mdbCfg.Length > 1)
                sw.WriteLine($"mariadb:user {mdbCfg[1]}");
            else
                sw.WriteLine($"#mariadb:user <username>");
            if(mdbCfg.Length > 2)
                sw.WriteLine($"mariadb:pass {mdbCfg[2]}");
            else
                sw.WriteLine($"#mariadb:pass <password>");
            if(mdbCfg.Length > 3)
                sw.WriteLine($"mariadb:db   {mdbCfg[3]}");
            else
                sw.WriteLine($"#mariadb:db   <database>");

            sw.Flush();
        }
    }
}