using SharpChat.Configuration;
using SharpChat.EventStorage;
using SharpChat.Flashii;
using System.Text;

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;

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

        if(hasCancelled) return;

        EventStorage.EventStorage 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(flashii, flashii, 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();
    }
}