using FNZCM.BlazorWasm.UI;
using FNZCM.BlazorWasm.UI.Components;
using FNZCM.Shared.Helpers;
using FNZCM.Shared.MediaModels;
using FNZCM.Shared.MetadataModels;
using Microsoft.AspNetCore.Components.WebAssembly.Http;
using Newtonsoft.Json;
using System.Net.Http.Json;

namespace FNZCM.BlazorWasm.Helpers
{
    public class ApiClient
    {
        private readonly HttpClient http;

        public Uri BaseAddress => http.BaseAddress;

        public ApiClient(HttpClient http) => this.http = http;

        public async Task<LoadingProgress> GetProgressAsync()
        {
            var url = $"metadata/progress.json";

            var response = await http.GetAsync(url);
            var obj = await response.Content.ReadFromJsonAsync<LoadingProgress>();
            return obj;
        }

        private async Task<string> GetStringAsync(string url)
        {
            var response = await http.GetAsync(url);
            var str = await response.Content.ReadAsStringAsync();
            return str;
        }

        public async Task<Dictionary<string, Library>> GetLibrariesAsync(ProgressBar[] progress)
        {
            var url = $"metadata/file-set.json";
            url += $"?etag={await GetStringAsync($"{url}/checksum")}";

            var request = new HttpRequestMessage(HttpMethod.Get, url);
            request.SetBrowserResponseStreamingEnabled(true);
            request.SetBrowserRequestCache(BrowserRequestCache.Default);

            var response = await http.SendAsync(request);
            var jsonStream = await response.Content.ReadAsStreamAsync();

            using var streamReader = new StreamReader(jsonStream);
            using var jsonReader = new JsonTextReader(streamReader);
            var serializer = new JsonSerializer();

            if (!jsonReader.Read()) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
            if (jsonReader.TokenType != JsonToken.StartObject) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");

            var obj = new Dictionary<string, Library>();
            while (true)
            {
                await progress[0].SetProgress((float)jsonStream.Position / jsonStream.Length, $"Loading fileset {jsonStream.Position.BytesToFileSize()}/{jsonStream.Length.BytesToFileSize()}...");

                if (!jsonReader.Read()) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                if (jsonReader.TokenType == JsonToken.EndObject) break;

                if (jsonReader.TokenType != JsonToken.PropertyName) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                var key = (string)jsonReader.Value;

                if (!jsonReader.Read()) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                if (jsonReader.TokenType != JsonToken.StartObject) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                obj[key] = serializer.Deserialize<Library>(jsonReader);
            }
            await progress[0].SetProgress((float)jsonStream.Position / jsonStream.Length, $"Loading fileset {jsonStream.Position.BytesToFileSize()}/{jsonStream.Length.BytesToFileSize()}...OK", true);
            return obj;
        }

        public async Task<Dictionary<string, MediaTag>> GetMediaTagsAsync(ProgressBar[] progress = null)
        {
            var url = $"metadata/tag-dict.json";
            url += $"?etag={await GetStringAsync($"{url}/checksum")}";

            var request = new HttpRequestMessage(HttpMethod.Get, url);

            request.SetBrowserResponseStreamingEnabled(true);
            request.SetBrowserRequestCache(BrowserRequestCache.Default);

            var response = await http.SendAsync(request);
            var jsonStream = await response.Content.ReadAsStreamAsync();

            using var streamReader = new StreamReader(jsonStream);
            using var jsonReader = new JsonTextReader(streamReader);
            var serializer = new JsonSerializer();

            if (!jsonReader.Read()) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
            if (jsonReader.TokenType != JsonToken.StartObject) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");

            var obj = new Dictionary<string, MediaTag>();
            while (true)
            {
                await progress[1].SetProgress((float)jsonStream.Position / jsonStream.Length, $"Loading tags {jsonStream.Position.BytesToFileSize()}/{jsonStream.Length.BytesToFileSize()}...");

                if (!jsonReader.Read()) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                if (jsonReader.TokenType == JsonToken.EndObject) break;

                if (jsonReader.TokenType != JsonToken.PropertyName) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                var key = (string)jsonReader.Value;

                if (!jsonReader.Read()) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                if (jsonReader.TokenType != JsonToken.StartObject) throw new JsonException($"Deserialization failed at line {jsonReader.LineNumber} position {jsonReader.LinePosition}.");
                obj[key] = serializer.Deserialize<MediaTag>(jsonReader);
            }

            await progress[1].SetProgress((float)jsonStream.Position / jsonStream.Length, $"Loading tags {jsonStream.Position.BytesToFileSize()}/{jsonStream.Length.BytesToFileSize()}...OK", true);


            return obj;
        }

        public async Task ReloadBackEnd(string password, bool? flag)
        {
            var url = flag switch
            {
                null => "admin/?action=ReloadModules&pass=" + password,
                true => "admin/?action=ReloadFully&pass=" + password,
                false => "admin/?action=Reload&pass=" + password,
            };

            var request = new HttpRequestMessage(HttpMethod.Get, url);

            request.SetBrowserRequestCache(BrowserRequestCache.Default);

            var response = await http.SendAsync(request);
            var text = await response.Content.ReadAsStringAsync();
        }
    }
}
