using System;
using System.IO;
using System.Net;
using System.Text;
using System.Linq;
using UnityEngine;
using Newtonsoft.Json.Linq;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text.RegularExpressions;

public class UpdateChecker : MonoBehaviour
{
    public void RequestUpdate()
    {
        var version = Settings.GameVersion;
        var bundleUrl = "";

        try { version = GetAndroidVersion(); }
        catch { Error.Log(Color.red, $"Failed getting game version. Using {version} from settings"); }

        if(version != Settings.GameVersion)
        {
            Settings.Instance.gameVersion = version;
            Settings.Save();
        }

        try { bundleUrl = GetAssetbundleUrl(version); }
        catch { Error.Log(Color.red, $"Failed getting assets url"); return; }

        if(bundleUrl != Settings.AssetsUrl)
        {
            if(UpdateUrlFile(bundleUrl))
                Error.Log(Color.green, "Update Successful! Please restart the viewer to download new files.");
        }
        else
        {
            Error.Log(Color.green, "You already have the newest files!");
        }
    }

    public string GetAndroidVersion()
    {
        string url = "https://play.google.com/store/apps/details?id=com.sega.KemonoFriends3";

        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
        using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse())
        using (Stream stream = httpResponse.GetResponseStream())
        using (StreamReader stringReader = new StreamReader(stream))
        {
            var response = stringReader.ReadToEnd();
            var result = Regex.Match(response, @"""\b(\d+\.\d+\.\d+)\b""");
            return result.Groups[1].Value;
        }
    }

    public string GetAssetbundleUrl(string version)
    {
        string param = Encode($"{{'version':'{version}','dmm_viewer_id':0,'platform':1}}".Replace("'", "\""));
        Debug.Log(param);

        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("https://parade-mobile-prod-app.kemono-friends-3.jp/paradesv/common/GetUrl.do?param=" + param);
        httpRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0";
        httpRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

        using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse())
        using (Stream stream = httpResponse.GetResponseStream())
        using (Stream decompress = new GZipStream(stream, CompressionMode.Decompress))
        using (StreamReader stringReader = new StreamReader(decompress))
        {
            var response = stringReader.ReadToEnd();
            var json = JObject.Parse(response);
            return json["asset_bundle_url"].ToString();
        }
    }

    private bool UpdateUrlFile(string newVersion)
    {
        try
        {
            if (File.Exists(Path.Combine(Settings.AssetListDirectory, "ab_list.txt")))
            {
                File.Delete(Path.Combine(Settings.AssetListDirectory, "ab_list.txt"));
            }
            Settings.Instance.assetsUrl = newVersion;
            Settings.Save();
            return true;
        }
        catch (Exception e)
        {
            Debug.LogError(e.Message);
            return false;
        }
    }

    public string Encode(string request)
    {
        MD5 md5 = MD5.Create();

        string hashed = GetMd5Hash(md5, request);
        string checksum = GetMd5Hash(md5, request + "DARAPAB ");
        string key = BytesToHexString(md5.ComputeHash(HexStringToByteArray(hashed.Substring(0, 8))));

        //xor with the key
        byte[] requestBytes = Encoding.ASCII.GetBytes(request);
        byte[] keyBytes = HexStringToByteArray(key);

        for (int i = 0; i < requestBytes.Length; i++)
        {
            requestBytes[i] ^= keyBytes[i % keyBytes.Length];
        }

        request = (hashed.Substring(0, 8) + BytesToHexString(requestBytes) + checksum);

        return request;
    }

    public string Decode(string request)
    {
        MD5 md5 = MD5.Create();

        string key = BytesToHexString(md5.ComputeHash(HexStringToByteArray(request.Substring(0, 8))));
        string hash = request.Substring(8, request.Length - 40);

        byte[] requestBytes = HexStringToByteArray(hash);
        byte[] keyBytes = HexStringToByteArray(key);

        for (int i = 0; i < requestBytes.Length; i++)
        {
            requestBytes[i] ^= keyBytes[i % keyBytes.Length];
        }

        return Encoding.UTF8.GetString(requestBytes);
    }

    public string GetMd5Hash(MD5 md5Hash, string input)
    {
        // Convert the input string to a byte array and compute the hash.
        byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

        // Create a new Stringbuilder to collect the bytes
        // and create a string.
        StringBuilder sBuilder = new StringBuilder();

        // Loop through each byte of the hashed data
        // and format each one as a hexadecimal string.
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("x2"));
        }

        // Return the hexadecimal string.
        return sBuilder.ToString();
    }

    public byte[] HexStringToByteArray(string hex)
    {
        return Enumerable.Range(0, hex.Length)
                         .Where(x => x % 2 == 0)
                         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                         .ToArray();
    }

    public string BytesToHexString(byte[] data)
    {
        StringBuilder sBuilder = new StringBuilder();

        // Loop through each byte of the hashed data
        // and format each one as a hexadecimal string.
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("x2"));
        }

        // Return the hexadecimal string.
        return sBuilder.ToString();
    }
}
