using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.IO;
using LKFWSContracts;

namespace LKFWSClient.WSClient
{
    public class LKFClientSession
    {
        string _url;
        string _serverVersion;
        uint _minModelYear;
        uint _maxModelYear;

        HttpClient _client;
        ILKFClientLog _logger;

        public LKFClientSession(string url, ILKFClientLog logger)
        {
            _url = url;
            _logger = logger;
        }

        public ILKFClientLog Logger
        {
            get
            {
                return _logger;
            }
            set
            {
                _logger = value;
            }
        }

        public async Task<bool> Connect()
        {
            HttpClientHandler clientHandler = new HttpClientHandler();
            HttpClient client = new HttpClient(clientHandler);
            client.BaseAddress = new Uri(_url);
            //client.DefaultRequestHeaders.Accept.Clear();
            //client.DefaultRequestHeaders.Accept.Add(
            //    new MediaTypeWithQualityHeaderValue("application/json"));
            if (_logger != null)
            {
                _logger.Log("calling api/LKFProcessor to connect");
            }
            var response = await client.GetStringAsync("api/LKFProcessor");
            if (_logger != null)
            {
                _logger.Log(string.Format("response: {0}", response));
            }

            _client = client;
            var serverInfo = JsonSerializer.Deserialize(response, typeof(ServerInfo)) as ServerInfo;

            if (_logger != null)
            {
                _logger.AppendLogLine(string.Format("deserialized: {0}", serverInfo.ToString()), LKFClientLogLevel.Info);
            }


            _serverVersion = serverInfo.version;
            _minModelYear = serverInfo.minimumModelYear;
            _maxModelYear = serverInfo.maximumModelYear;

            return true;
        }

        public async Task<bool> UploadFile (string fileName)
        {
            if (_logger != null)
            {
                _logger.Log($"uploading data file {fileName}");
            }

            try
            {

                var formContent = new System.Net.Http.MultipartFormDataContent();

                var stream = File.OpenRead(fileName);
                var fileContent = new StreamContent(stream);
                formContent.Add(fileContent, fileName);

                //var byteArrayContent = new ByteArrayContent(File.ReadAllBytes(fileName));
                //byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain");
                //formContent.Add(byteArrayContent);

                var response = await _client.PostAsync("api/LKFProcessor/sendrows", formContent);
                return true;
            }
            catch (Exception ex)
            {
                if (_logger != null)
                {
                    _logger.LogException(ex);
                }
                return false;
            }
        }

        public async Task<byte[]> GetResultFile()
        {
            return await GetFile("api/LKFProcessor/resultFile");
        }

        public async Task<byte[]> GetWarningFile()
        {
            return await GetFile("api/LKFProcessor/warningFile");
        }

        public async Task<byte[]> GetErrorFile()
        {
            return await GetFile("api/LKFProcessor/errorFile");
        }

        public async Task<byte[]> GetInfoFile()
        {
            return await GetFile("api/LKFProcessor/infoFile");
        }


        private async Task<byte[]> GetFile(string api)
        {
            if (_logger != null)
            {
                _logger.Log($"getting {api}");
            }
            try
            {
                var doc = await _client.GetAsync(api);

                if (doc != null && doc.Content != null)
                {
                    return await doc.Content.ReadAsByteArrayAsync();
                }
                else if (_logger != null)
                {
                    _logger.Log("invalid response");
                }
            }
            catch (Exception ex)
            {
                if (_logger != null)
                {
                    _logger.LogException(ex);
                }
            }
            return null;
        }


        public async Task<bool> Prepare(PrepareData prepareData)
        {
            var contentString = JsonSerializer.Serialize(prepareData);
            StringContent content = new StringContent(contentString, UnicodeEncoding.UTF8, "application/json");
            if (_logger != null)
            {
                _logger.Log("sending PrepareData");
            }

            var response = await _client.PostAsync("api/LKFProcessor/prepareData", content);

            var streamResponseContent = response.Content as System.Net.Http.HttpContent;
            if (streamResponseContent == null)
            {
                if (_logger != null)
                {
                    _logger.Error("did not return stream content");
                    return false;
                }
            }

            var json = await streamResponseContent.ReadAsStringAsync();
            var prepareDataResponse = JsonSerializer.Deserialize(json, typeof(PrepareDataResponse)) as PrepareDataResponse;

            if (!prepareDataResponse.success)
            {
                if (_logger != null)
                {
                    _logger.Error("failed");
                    foreach (var s in prepareDataResponse.errors)
                    {
                        _logger.Error(s);
                    }
                }
                return false;
            }
            else
            {
                if (_logger != null)
                {
                    _logger.Log("success");
                }
                return true;
            }
        }

        public async Task<ComputeResponse> Compute(Compute computeRequest)
        {
            var contentString = JsonSerializer.Serialize(computeRequest);
            StringContent content = new StringContent(contentString, UnicodeEncoding.UTF8, "application/json");
            if (_logger != null)
            {
                _logger.Log("sending Compute");
            }

            var response = await _client.PostAsync("api/LKFProcessor/compute", content);

            var streamResponseContent = response.Content as System.Net.Http.HttpContent;
            if (streamResponseContent == null)
            {
                if (_logger != null)
                {
                    _logger.Error("did not return stream content");
                    return null;
                }
            }

            var json = await streamResponseContent.ReadAsStringAsync();
            var computeResponse = JsonSerializer.Deserialize(json, typeof(ComputeResponse)) as ComputeResponse;

            if (_logger != null)
            {
                _logger.Log(string.Format("{0} cases, {1} points, {2} errors, {3} warnings, {4} infos", computeResponse.caseCount, computeResponse.sumPoints, computeResponse.errorCount, computeResponse.warningCount, computeResponse.infoCount));
            }

            return computeResponse;
        }

        public string ServerVersion => _serverVersion;
        public uint MinModelYear => _minModelYear;
        public uint MaxModelYear => _maxModelYear;

    }
}
