namespace ProtonPlus.Models {
    public class SteamProfile : Object {
        const int64 steamid64ident = 76561197960265728;
        public Launchers.Steam launcher { get; set; }
        public string userdata_path { get; set; }
        public string localconfig_path { get; set; }
        public VDF.Shortcuts shortcuts { get; set; }
        public string steam_id { get; set; }
        public string account_id { get; set; }
        public string username { get; set; }
        public string image_path { get; set; }
        public string default_compatibility_tool { get; set; }
        public HashTable<uint, string> launch_options_hashtable;
        public List<Games.Steam> non_steam_games;

        public SteamProfile (Launchers.Steam launcher, string username, string steam_id, string userdata_path) {
            this.launcher = launcher;
            this.steam_id = steam_id;
            this.username = username;
            this.userdata_path = userdata_path;

            this.account_id = steam_id_to_account_id (steam_id);

            this.localconfig_path = "%s/config/localconfig.vdf".printf (userdata_path);

            this.image_path = "%s/config/avatarcache/%s.png".printf (launcher.directory, steam_id);

            try {
                var shortcuts_file_path = "%s/config/shortcuts.vdf".printf (userdata_path);

                if (!FileUtils.test (shortcuts_file_path, FileTest.IS_REGULAR))
                VDF.Shortcuts.create_new_shortcuts_file_at (shortcuts_file_path);

                shortcuts = new VDF.Shortcuts (shortcuts_file_path);
            } catch (Error e) {
                warning (e.message);
            }
        }

        public async bool load_extra_data () {
            var launch_options_loaded = yield load_launch_options ();
            if (!launch_options_loaded)
            return false;

            var non_steam_games_loaded = yield load_non_steam_games ();
            if (!non_steam_games_loaded)
            return false;

            return true;
        }

        async bool load_launch_options () {
            this.launch_options_hashtable = new HashTable<uint, string> (null, null);

            var content = Utils.Filesystem.get_file_content (localconfig_path);
            var start_text = "";
            var end_text = "";
            var start_pos = 0;
            var end_pos = 0;
            var apps = "";
            var app = "";
            var id_text = "";
            var id_valid = false;
            var id = 0;
            var launch_options = "";

            start_text = "apps\"\n\t\t\t\t{";
            start_pos = content.index_of (start_text, 0) + start_text.length;

            if (start_pos == -1)
            return false;

            end_text = "\n\t\t\t\t}";
            end_pos = content.index_of (end_text, start_pos);

            if (end_pos == -1)
            return false;

            apps = content.substring (start_pos, end_pos - start_pos);
            // message("start: %i, end: %i, apps: %s", start_pos, end_pos, apps);

            var position = 0;
            while (true) {
                start_text = "\"";
                start_pos = apps.index_of (start_text, position);

                if (start_pos == -1)
                break;

                end_text = "\n\t\t\t\t\t}";
                position = end_pos = apps.index_of (end_text, start_pos + start_text.length) + end_text.length;

                if (end_pos == -1)
                break;

                app = apps.substring (start_pos, end_pos - start_pos);
                // message("start: %i, end: %i, app: %s", start_pos, end_pos, app);

                if (app.contains ("LaunchOptions")) {
                    start_text = "\"";
                    start_pos = app.index_of (start_text, 0) + start_text.length;

                    if (start_pos == -1)
                    break;

                    end_text = "\"";
                    end_pos = app.index_of (end_text, start_pos);

                    if (end_pos == -1)
                    break;

                    id_text = app.substring (start_pos, end_pos - start_pos);
                    // message("start: %i, end: %i, id: %s", start_pos, end_pos, id_text);

                    id_valid = int.try_parse (id_text, out id);
                    if (!id_valid)
                    break;

                    start_text = "LaunchOptions\"\t\t\"";
                    start_pos = app.index_of (start_text, 0) + start_text.length;

                    if (start_pos == -1)
                    break;

                    end_text = "\"\n\t";
                    end_pos = app.index_of (end_text, start_pos);

                    if (end_pos == -1)
                    break;

                    launch_options = app.substring (start_pos, end_pos - start_pos).replace ("\\\"", "\"");
                    // message("start: %i, end: %i, launch_options: %s", start_pos, end_pos, launch_options);

                    launch_options_hashtable.set (id, launch_options);
                }
            }

            foreach (var game in (List<Games.Steam>) launcher.games) {
                launch_options = launch_options_hashtable.get (game.appid);
                if (launch_options == null)
                launch_options = "";
                this.launch_options_hashtable.set (game.appid, launch_options);
            }

            return true;
        }

        async bool load_non_steam_games () {
            this.non_steam_games = new List<Games.Steam> ();

            foreach (var entry in shortcuts.nodes.entries) {
                if (entry.key.contains ("shortcuts.") && !entry.key.contains (".tags")) {
                    uint appid = entry.value.get ("appid").get_int32 ();
                    if (appid < 0)
                    appid += (1u << 32);

                    if (!entry.value.has_key ("AppName"))
                    continue;

                    string name = entry.value.get ("AppName").get_string ();
                    if (name == "ProtonPlus")
                    continue;

                    string launch_options = entry.value.get ("LaunchOptions").get_string ().replace ("\\\"", "\"");

                    var compatibility_tool = launcher.compatibility_tool_hashtable.get (appid);
                    if (compatibility_tool == null)
                    compatibility_tool = "Undefined";

                    var game = new Games.Steam.non_steam (appid, name, launch_options, compatibility_tool, launcher);

                    non_steam_games.append (game);
                }
            }

            return true;
        }

        static string steam_id_to_account_id (string steam_id) {
            var steam_id2 = "STEAM_0:";
            var steam_id2_account = int64.parse (steam_id) - steamid64ident;

            if (steam_id2_account % 2 == 0)
            steam_id2 += "0:";
            else
            steam_id2 += "1:";

            steam_id2 += Math.floor (steam_id2_account / 2).to_string ();

            // message("SteamID2: %s".printf (steam_id2));

            var steam_id2_split = steam_id2.split (":");
            var steam_id3 = "[U:1:";

            var y = int.parse (steam_id2_split[1]);
            var z = int.parse (steam_id2_split[2]);

            var account_id = z * 2 + y;

            steam_id3 += "%i]".printf (account_id);

            // message("SteamID3: %s".printf (steam_id3));

            return account_id.to_string ();
        }

        static string account_id_to_steam_id (string account_id) {
            var steam_id = int64.parse (account_id) + steamid64ident;

            return steam_id.to_string ();
        }

        public static List<SteamProfile> get_profiles (Launchers.Steam launcher) {
            var profiles = new List<SteamProfile> ();

            var path = "%s/config/loginusers.vdf".printf (launcher.directory);
            var content = Utils.Filesystem.get_file_content (path);
            if (content.length == 0)
            return profiles;
            var start_text = "";
            var end_text = "";
            var start_pos = 0;
            var end_pos = 0;
            var users = "";
            var user = "";
            var id = "";
            var username = "";
            var userdata_path = "";

            var userdata_hashtable = get_userdata_hashtable (launcher);

            start_text = "users\"\n{";
            start_pos = content.index_of (start_text, 0) + start_text.length;

            end_pos = content.length - 3;

            users = content.substring (start_pos, end_pos - start_pos);
            // message("start: %i, end: %i, users: %s", start_pos, end_pos, users);

            int position = 0;
            while (true) {
                start_text = "\"";
                start_pos = users.index_of (start_text, position);
                if (start_pos == -1)
                break;

                end_text = "}";
                position = end_pos = users.index_of (end_text, start_pos + start_text.length) + 1;
                if (end_pos == -1)
                break;

                user = users.substring (start_pos, end_pos - start_pos);
                // message("start: %i, end: %i, user: %s", start_pos, end_pos, user);

                start_text = "\"";
                start_pos = user.index_of (start_text, 0) + start_text.length;
                if (start_pos == -1)
                break;

                end_text = "\"";
                end_pos = user.index_of (end_text, start_pos);
                if (end_pos == -1)
                break;

                id = user.substring (start_pos, end_pos - start_pos);
                // message ("start: %i, end: %i, id: %s", start_pos, end_pos, id);

                start_text = "PersonaName\"\t\t\"";
                start_pos = user.index_of (start_text, 0) + start_text.length;
                if (start_pos == -1)
                break;

                end_text = "\"";
                end_pos = user.index_of (end_text, start_pos);
                if (end_pos == -1)
                break;

                username = user.substring (start_pos, end_pos - start_pos);
                // message ("start: %i, end: %i, username: %s", start_pos, end_pos, username);

                userdata_path = userdata_hashtable.get (id);
                if (userdata_path == null)
                continue;

                var profile = new SteamProfile (launcher, username, id, userdata_path);

                profiles.append (profile);
            }

            return profiles;
        }

        static HashTable<string, string> get_userdata_hashtable (Launchers.Steam launcher) {
            var userdata_hashtable = new HashTable<string, string> (str_hash, str_equal);

            try {
                var userdata_path = "%s/userdata".printf (launcher.directory);
                if (FileUtils.test (userdata_path, FileTest.IS_DIR)) {
                    Dir directory = Dir.open (userdata_path);
                    string? dir;
                    while ((dir = directory.read_name ()) != null) {
                        if (dir != "." && dir != "..") {
                            File file = File.new_for_path (userdata_path + "/" + dir);
                            if (file.query_file_type (FileQueryInfoFlags.NONE) == FileType.DIRECTORY) {
                                userdata_hashtable.set (account_id_to_steam_id (dir), file.get_path ());
                            }
                        }
                    }
                }
            } catch (Error e) {
                warning (e.message);
            }

            return userdata_hashtable;
        }
    }
}
