using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace nuget_cli
{
    public class NugetdErrorMessage
    {
        public string versionId { get; set; }
        public int ecode { get; set; }
        public string msg { get; set; }
    }
    public class UploadFilesToServerUsingWebRequest
    {

        /// <summary>
        /// Creates HTTP POST request &amp; uploads database to server. Author : Farhan Ghumra
        /// </summary>
        internal async Task UploadFilesToServerAsync(PushReport report, Uri uri, FileInfo fi,
       string apikey)
        {
            // string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
            const int TXLEN = 0x1000;
            /// the form-data file upload, properly formatted
            string fileheaderTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\";\r\nContent-Type: {2}\r\n\r\n";

            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

            // "X-NuGet-ApiKey
            string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
            string fileheader = string.Format(fileheaderTemplate, "file", fi.Name, "application/octet-stream");
            byte[] fileheaderbytes = Encoding.ASCII.GetBytes(fileheader);
            var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
            var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);

            httpWebRequest.Method = "PUT";
            httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
            httpWebRequest.AllowAutoRedirect = false;
            httpWebRequest.Headers.Add("X-NuGet-Client-Version", Constants.ClientVersion);
            httpWebRequest.Headers.Add("X-NuGet-ApiKey", apikey);
            httpWebRequest.ContentLength = boundarybytes.Length +
              fileheaderbytes.Length + fi.Length + endBoundaryBytes.Length;


            httpWebRequest.BeginGetRequestStream(async (result) =>
            {
                try
                {
                    HttpWebRequest request = (HttpWebRequest)result.AsyncState;

                    using (Stream requestStream = request.EndGetRequestStream(result))
                    {
                       await WriteToStream(requestStream, boundarybytes, boundarybytes.Length);
                        await WriteToStream(requestStream, fileheaderbytes, fileheaderbytes.Length);
                        using (var fss = fi.OpenRead())
                        {
                            byte[] buffer = new byte[TXLEN];
                            var form_bytes_read = fss.Read(buffer, 0, TXLEN);
                            while (form_bytes_read > 0)
                            {
                                await WriteToStream(requestStream, buffer, form_bytes_read);
                                form_bytes_read = fss.Read(buffer, 0, TXLEN);
                            }
                        }
                        requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
                        requestStream.Close();
                    }
                }
                catch (Exception rex)
                {
                    report.Message = rex.Message;
                    Console.Error.WriteLine(rex.Message);
#if DEBUG
                    Console.Error.WriteLine("Stack trace:");
                    Console.Error.WriteLine(rex.StackTrace);
#endif
                }
            }, httpWebRequest);

            WebResponse resp = await httpWebRequest.GetResponseAsync();

            Stream stream = resp.GetResponseStream();
            StreamReader re = new StreamReader(stream);
            if (resp is HttpWebResponse)
            {
                String json = await re.ReadToEndAsync();
                report.Message = json;
                var hrep = resp as HttpWebResponse;
                report.StatusCode = hrep.StatusCode.ToString();
                report.OK = hrep.StatusCode == HttpStatusCode.Accepted
                 || hrep.StatusCode == HttpStatusCode.OK;
            }
            else throw new Exception("Invalid server response type");
        }

        /// <summary>
        /// Writes byte array to stream. Author : Farhan Ghumra
        /// </summary>
        private static async Task WriteToStream(Stream s, byte[] bytes, int len)
        {
            await s.WriteAsync(bytes, 0, len);
        }
    }
}