using ModMenu;
using Func;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Encodings.Web;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Text.Json.Serialization;
using System.Security.Cryptography.X509Certificates;

namespace TelemetryWebpost {
    public class SplatTelemetry {
        private static readonly HttpClient client = new HttpClient();
        public static uint LastStartNetworkTime = 0;

        public static string Telemetry2Json(byte[] rawData)  {
            if (rawData == null || rawData.Length == 0)
                return "{}";

            int actualStart = Array.IndexOf(rawData, (byte)0x2D);
            if (actualStart == -1) return "{}";

            string content = Encoding.UTF8.GetString(rawData, actualStart, rawData.Length - actualStart);

            string[] lines = content.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
            if (lines.Length == 0 || string.IsNullOrWhiteSpace(lines[0]))
                return "{}";

            string boundary = lines[0].Trim();

            string[] parts = content.Split(new[] { boundary }, StringSplitOptions.RemoveEmptyEntries);
            var result = new Dictionary<string, string>();

            foreach (var part in parts) {
                if (string.IsNullOrWhiteSpace(part) ||
                    part.Trim() == "--" ||
                    part.Contains("name=\"FaceImg\"") || // Kit Kat said he doesnt need faceimg.tga so i'll skip it :innocent:, makes my life easier.
                    !part.Contains("Content-Disposition"))
                {
                    continue;
                }

                var nameMatch = Regex.Match(part, "name=\"(?<name>[^\"]+)\"");
                if (!nameMatch.Success) continue;
                string key = nameMatch.Groups["name"].Value;

                int valueStart = part.IndexOf("\r\n\r\n");
                int offset = 4;

                if (valueStart == -1) {
                    valueStart = part.IndexOf("\n\n");
                    offset = 2;
                }

                if (valueStart == -1) continue;

                string value = part.Substring(valueStart + offset).Trim(new[] { '\r', '\n', '-', ' ' });

                result[key] = value;
            }

            var options = new JsonSerializerOptions {
                WriteIndented = true,
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };

            return JsonSerializer.Serialize(result, options);
        }

        public static async Task SendTelemetryHttp(string targetUrl, string uniqueId, string TelemetryPayload, byte[] faceImgData) {
            var TelemetryPayloadDict = JsonSerializer.Deserialize<Dictionary<string, string>>(TelemetryPayload);
            TelemetryPayloadDict["ServerEnv"] = "L1";
            if (LastStartNetworkTime == Convert.ToUInt32(TelemetryPayloadDict["StartNetworkTime"])) {
                Console.WriteLine("Data sent already...");
                return;
            }
            LastStartNetworkTime = Convert.ToUInt32(TelemetryPayloadDict["StartNetworkTime"]);
            try {
                using (var content = new MultipartFormDataContent()) {
                    foreach (var kvp in TelemetryPayloadDict) {
                        content.Add(new StringContent(kvp.Value), kvp.Key);
                    }

                    var imageContent = new ByteArrayContent(faceImgData);
                    imageContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
                    content.Add(imageContent, "FaceImg", "face.bin");

                    byte[] requestBody = await content.ReadAsByteArrayAsync();

                    string sha1Hash;
                    using (SHA1 sha1 = SHA1.Create()) {
                        byte[] hashBytes = sha1.ComputeHash(requestBody);
                        sha1Hash = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
                    }

                    var request = new HttpRequestMessage(HttpMethod.Post, targetUrl);
                    request.Content = content;

                    request.Headers.Add("X-BOSS-Digest", sha1Hash);
                    request.Headers.Add("X-BOSS-UniqueId", uniqueId);

                    Console.WriteLine($"Sending telemetry for {TelemetryPayloadDict["MiiName"]}...");
                    HttpResponseMessage response = await client.SendAsync(request);

                    if (response.IsSuccessStatusCode) {
                        Console.WriteLine("SUCCESS: Splatoon result saved.");
                    } else {
                        string errorText = await response.Content.ReadAsStringAsync();
                        Console.WriteLine($"FAILED: {(int)response.StatusCode} - {errorText}");
                    }
                }
            } catch (Exception ex) {
                Console.WriteLine($"Connection Error: {ex.Message}");
            }
        }

        public static void SendTelemetry()  {
            if (Program.readUInt32(0x101E4FF8) == 0) {
                var p = Program.readUInt32(0x101DCDB0) + 0x150;
                var data = Program.readBytes(p, 0x1800);

                byte[] faceimg_pattern = new byte[]{ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00 };
                int faceimg_offset = ExtFunc.FindPattern(data, faceimg_pattern);
                if (faceimg_offset == -1) {
                    return;
                }
                var faceimg = Program.readBytes((uint)(p + faceimg_offset), 65580);
                var TelemetryPayload = Telemetry2Json(data);
                // Console.WriteLine(TelemetryPayload);

                SendTelemetryHttp(Program.config["TelemetryUrl"], "0162b", TelemetryPayload, faceimg).GetAwaiter().GetResult();
            }
        }
    }
}