using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using TweetDuck.Core.Utils;
using JsonObject = System.Collections.Generic.IDictionary<string, object>;

namespace TweetDuck.Updates{
    sealed class UpdateCheckClient{
        private const string ApiLatestRelease = "https://api.github.com/repos/chylex/TweetDuck/releases/latest";
        private const string UpdaterAssetName = "TweetDuck.Update.exe";

        private readonly string installerFolder;

        public UpdateCheckClient(string installerFolder){
            this.installerFolder = installerFolder;
        }

        public Task<UpdateInfo> Check(){
            TaskCompletionSource<UpdateInfo> result = new TaskCompletionSource<UpdateInfo>();

            WebClient client = BrowserUtils.CreateWebClient();
            client.Headers[HttpRequestHeader.Accept] = "application/vnd.github.v3+json";

            client.DownloadStringTaskAsync(ApiLatestRelease).ContinueWith(task => {
                if (task.IsCanceled){
                    result.SetCanceled();
                }
                else if (task.IsFaulted){
                    result.SetException(ExpandWebException(task.Exception.InnerException));
                }
                else{
                    try{
                        result.SetResult(ParseFromJson(task.Result));
                    }catch(Exception e){
                        result.SetException(e);
                    }
                }
            });
            
            return result.Task;
        }

        private UpdateInfo ParseFromJson(string json){
            bool IsUpdaterAsset(JsonObject obj){
                return UpdaterAssetName == (string)obj["name"];
            }

            string AssetDownloadUrl(JsonObject obj){
                return (string)obj["browser_download_url"];
            }
            
            JsonObject root = (JsonObject)new JavaScriptSerializer().DeserializeObject(json);

            string versionTag = (string)root["tag_name"];
            string releaseNotes = (string)root["body"];
            string downloadUrl = ((Array)root["assets"]).Cast<JsonObject>().Where(IsUpdaterAsset).Select(AssetDownloadUrl).FirstOrDefault();

            return new UpdateInfo(versionTag, releaseNotes, downloadUrl, installerFolder);
        }

        private static Exception ExpandWebException(Exception e){
            if (e is WebException we && we.Response is HttpWebResponse response){
                try{
                    using(Stream stream = response.GetResponseStream())
                    using(StreamReader reader = new StreamReader(stream, Encoding.GetEncoding(response.CharacterSet ?? "utf-8"))){
                        return new Reporter.ExpandedLogException(e, reader.ReadToEnd());
                    }
                }catch{
                    // whatever
                }
            }

            return e;
        }
    }
}