using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TELTest.Matchmaking;

namespace TELTest {
    internal class GUIUtilities {
        public static async Task<string> Promptfull(ConnectionHandler handler, NetworkStream stream, string prompt, string @default = null, int nMax = 32, bool noClear = false) {
            if (!noClear)
                await handler.TryClear(stream);

            await handler.WriteASCII(stream, "\r\n" + prompt + ": ");
            var res = await handler.Read(stream, new ReadConfiguration() {
                Echo = true,
                MaxLength = nMax,
                FlushAfterReading = true,
                Terminator = '\r',
                Whitelist = Utilities.ALPHANUMERIC + " ?,.{}[]()/\\:;'\"'\b"
            });
            return string.IsNullOrWhiteSpace(res) ? @default : res;
        }
        public static async Task AskUsernameIfNeeded(ConnectionHandler handler, NetworkStream stream, bool force = false) {
            bool usrset = string.IsNullOrWhiteSpace(handler.PlayerName);
            if (!usrset && !force) return;
            while (true) {
                await handler.TryClear(stream);
                //await handler.WriteASCII(stream, "Musisz wybrac nick zanim rozpoczniesz gre multiplayer.\r\n\r\n");
                await handler.WriteASCII(stream, "Nick: ");
                string nam = await handler.Read(stream, new ReadConfiguration() {
                    Terminator = '\r',
                    Echo = true,
                    MaxLength = 32,
                    Whitelist = Utilities.ALPHANUMERIC,
                    FlushAfterReading = true,
                });
                handler.PlayerName = nam.Trim();
                if (!string.IsNullOrWhiteSpace(nam)) break;
            }
        }
        public static async Task<bool> LobbyAwait(ConnectionHandler handler, NetworkStream stream, Lobby lobby) {
            while (true) {
                string[][] menu = new string[1][];
                List<string> players = new List<string>();
                players.Add("Odswiez");
                players.Add("Gotowe...");
                players.Add("Wyjdz...");
                foreach (var item in lobby.Players) {
                    players.Add(item.PlayerName + (item.PlayerReady? "*" : ""));
                }
                menu[0] = players.ToArray();
                var res = await Create2DMenu(handler, stream, menu, new[] { "Identyfikator: [" + lobby.Identifier + "]" });
                if (res.Item2 == 1) return true;
                if (res.Item2 == 2) return false;
            }
        }
        public static async Task LobbySettings(ConnectionHandler handler, NetworkStream stream, Lobby lobby) {
            int lastsel = 7;
            while (true) {
                string[][] menu = new string[1][];
                menu[0] = new string[] {
                    /* 0 */ "Tryb gry: " + lobby.Gamemode.Name,
                    /* 1 */ "Quiz: " + lobby.Subject.Title,
                    /* 2 */ "----------------",
                    /* 3 */ "Nazwa: " + lobby.Name,
                    /* 4 */ "Publiczne? " + (lobby.AnnouncePublic? "Tak" : "Nie"),
                    /* 5 */ "Haslo: " + (lobby.Password != null? new string('*', lobby.Password.Length) : "[Brak]"),
                    /* 6 */ "Max graczy: " + (lobby.PlayerLimit == -1? "Bez limitu" : lobby.PlayerLimit + ""),
                    /* 7 */ "Gotowe."
                };
                var res = await Create2DMenu(handler, stream, menu, new[] { "Identyfikator: [" + lobby.Identifier + "]" }, defaulty: lastsel);
                var sel = res.Item2;
                if (sel == 3) {
                    await handler.TryClear(stream);
                    await handler.WriteASCII(stream, "Nazwa: ");
                    string nam = await handler.Read(stream, new ReadConfiguration() {
                        Terminator = '\r',
                        Echo = true,
                        MaxLength = 32,
                        Whitelist = Utilities.ALPHANUMERIC + " ",
                        FlushAfterReading = true,
                    });
                    lobby.Name = nam;
                }
                if (sel == 4) lobby.AnnouncePublic = !lobby.AnnouncePublic;
                if (sel == 5) {
                    await handler.TryClear(stream);
                    await handler.WriteASCII(stream, "Haslo: ");
                    string nam = await handler.Read(stream, new ReadConfiguration() {
                        Terminator = '\r',
                        MaxLength = 32,
                        Echo = true,
                        EchoPasswordChars = true,
                        PasswordChar= '*',
                        FlushAfterReading = true,

                    });
                    nam = nam.Trim();
                    lobby.Password = string.IsNullOrEmpty(nam) ? null : nam;

                }
                if (sel == 6) {
                    await handler.TryClear(stream);
                    await handler.WriteASCII(stream, "Max: ");
                    string nam = await handler.Read(stream, new ReadConfiguration() {
                        Terminator = '\r',
                        Echo = true,
                        MaxLength = 32,
                        Whitelist = "0123456789",
                        FlushAfterReading = true,
                    });
                    if (string.IsNullOrWhiteSpace(nam)) {
                        lobby.PlayerLimit = -1;
                    } else {
                        lobby.PlayerLimit = int.Parse(nam);
                    }
                }
                if (sel == 7) break;
                lastsel = sel;
            }
        }
        public static async Task<Tuple<int, int>> Create2DMenu(ConnectionHandler handler, NetworkStream stream, string[][] menu, string[] labels, string caption = null, int defaultx = 0, int defaulty = 0) {
            int xsel = defaultx;
            int ysel = defaulty;
            while (true) {
                await handler.TryClear(stream);
                StringBuilder sb = new StringBuilder();
                if (caption != null)
                    sb.AppendLineRN(caption);
                //sb.AppendLineRN("Wybierz menu/widok/katalog klawiszami A/D.\r\n");
                if (labels.Length > xsel) {
                    if (xsel != 0)
                        sb.Append(labels[xsel - 1] + " <-- ");

                    sb.Append("[" + (labels[xsel] != null ? labels[xsel] : "Bez nazwy") + "]");

                    if (xsel != menu.Length - 1)
                        sb.AppendLineRN(" --> " + labels[xsel + 1]);
                    else
                        sb.AppendLineRN();

                    sb.AppendLineRN();
                }
                //for (int i = 0; i < menu.Length; i++) {
                int off = 0;
                if (ysel > 20) {
                    off = ysel / 20 * 20;
                }
                if (off != 0) sb.AppendLineRN("    [... + " + off + "]");
                for (int j = off; j < menu[xsel].Length; j++) {
                    bool t = ysel == j;
                    string name = menu[xsel][j];
                    if (name != null && name.StartsWith("FILE:")) name = Path.GetFileName(name.Substring(5));
                    sb.AppendLineRN((t ? " -> " : "    ") + name + "    ");
                    if (j - off > 20) {
                        sb.AppendLineRN("[... +" + (menu[xsel].Length - (off + 20)) + "]");
                        break;
                    }
                }
                //sb.AppendLineRN();
                //}
                sb.Append("\r\n[W/A/S/D/ENTER] ");
                await handler.WriteASCII(stream, sb.ToString());
                char c = char.ToUpper(await handler.ReadChar(stream, false));
                if (c == '\n' || c == '\r') {
                    handler.Flush(stream);
                    break;
                }
                if (c == 'W') {
                    if (ysel == 0) {
                        ysel = menu[xsel].Length - 1;
                    } else {
                        ysel--;
                    }
                }
                if (c == 'S') {
                    if (ysel == menu[xsel].Length - 1) {
                        ysel = 0;
                    } else {
                        ysel++;
                    }
                }

                if (c == 'A') {
                    if (xsel == 0) {
                        xsel = menu.Length - 1;
                    } else {
                        xsel--;
                    }
                }
                if (c == 'D') {
                    if (xsel == menu.Length - 1) {
                        xsel = 0;
                    } else {
                        xsel++;
                    }
                }
                if (menu[xsel].Length - 1 < ysel) ysel = menu[xsel].Length - 1;
            }
            return new Tuple<int, int>(xsel, ysel);
        }
    }
}
