using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Net;
using System.Text;
using System.Web;

namespace minimalist_oauth_rp.Models
{
    internal class SignManager
    {
        Uri documentsUrl;
        Uri processesUrl;
        Uri redirectUrl;

        internal SignManager(Uri hostname, string trustedxResourcesBaseUri)
        {
            this.documentsUrl = new Uri(string.Concat(trustedxResourcesBaseUri, "/esignsp/v2/documents"));
            this.processesUrl = new Uri(string.Concat(trustedxResourcesBaseUri, "/esignsp/v2/signer_processes"));
            this.redirectUrl = new Uri(hostname.Scheme + "://" + hostname.Authority + "/Signature/documentsSignatureEnd");
        }

        /// <summary>
        /// Se encarga de subir los documentos al servidor de TrustedX.
        /// </summary>
        /// <param name="filesToSign"></param>
        /// <param name="mimeType"></param>
        /// <returns>Una lista con los identificadores de los documentos subidos.</returns>
        internal List<KeyValuePair<string, string>> UploadFilesToSign(List<UploadFile> filesToSign, String mimeType, String accessToken)
        {
            List<KeyValuePair<string, string>> idNameList = new List<KeyValuePair<string, string>>();
            HttpClient httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
            foreach (UploadFile uploadFile in filesToSign)
            {
                ByteArrayContent byteArrayContent = new ByteArrayContent(uploadFile.FileToSign);
                byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse(mimeType);
                StringContent stringContent = new StringContent("[]", Encoding.UTF8, "application/json");
                var response = httpClient.PostAsync(documentsUrl, new MultipartFormDataContent {
                    { stringContent, "\"signers\""},
                    { byteArrayContent, "\"document\"", uploadFile.FileName}
                });
                var responseResult = response.Result.Content.ReadAsStringAsync();
                string jsonRespuesta = responseResult.Result;
                idNameList.Add(new KeyValuePair<string,string>(ObtenerId(jsonRespuesta), uploadFile.FileName));
            }
            return idNameList;
        }

        /// <summary>
        /// Actualiza los identificadores de los documentos en el JSON de entrada.
        /// </summary>
        /// <param name="idList">Lista con los identificadores de los documentos</param>
        /// <param name="jsonInput">JSON de entrada</param>
        /// <returns>JSON con el elemento "documents" actualizado</returns>
        internal string ActualizarDocumentos(List<string> idList, string jsonInput)
        {
            JArray jArray = new JArray();
            JObject jObject;
            foreach (String id in idList)
            {
                jObject = new JObject
                {
                    { "id", id }
                };
                jArray.Add(jObject);
            }
            var jsonVal = JObject.Parse(jsonInput);
            jsonVal["documents"] = jArray;
            return jsonVal.ToString();
        }

        internal string ActualizarRedirectUri(string jsonInput)
        {
            var jsonVal = JObject.Parse(jsonInput);
            jsonVal["finish_callback_url"] = this.redirectUrl;
            return jsonVal.ToString();
        }

        internal InicioProcesoFirmaResponse ObtenerUrlsFirma(string jsonFirma)
        {
            InicioProcesoFirmaResponse inicioProcesoFirmaResponse = new InicioProcesoFirmaResponse();
            var jsonVal = JObject.Parse(jsonFirma);
            var kk = jsonVal["documents"];
            inicioProcesoFirmaResponse.SignedId = jsonVal["id"].ToString();
            inicioProcesoFirmaResponse.UrlSignatureProcess = jsonVal["self"].ToString();
            inicioProcesoFirmaResponse.UrlUserRedirectAuthorization = jsonVal.SelectToken("tasks.pending[0].url").ToString();
            inicioProcesoFirmaResponse.DocumentsContent = new List<string>();
            inicioProcesoFirmaResponse.DocumentsUrl = new List<string>();
            foreach (JToken document in jsonVal["documents"])
            {
                inicioProcesoFirmaResponse.DocumentsContent.Add(document["content"].ToString());
                inicioProcesoFirmaResponse.DocumentsUrl.Add(document["url"].ToString());
            }
            return inicioProcesoFirmaResponse;
        }

        /// <summary>
        /// Extrae el identificador del documento del JSON de entrada.
        /// </summary>
        /// <param name="jsonRespuesta"></param>
        /// <returns>El identificador del documento</returns>
        internal String ObtenerId(string jsonRespuesta)
        {
            var jsonVal = JObject.Parse(jsonRespuesta);
            String idToken = jsonVal["id"].ToString();
            return idToken;
        }

        internal string IniciarProcesoFirma(string jsonInput, string accessToken)
        {
            WebClient webClient = new WebClient();
            webClient.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + accessToken);
            webClient.Headers.Add(HttpRequestHeader.ContentType, "application/json");
            string jsonResponse = webClient.UploadString(this.processesUrl, jsonInput);
            return jsonResponse;
        }

        /// <summary>
        /// Método que se encarga de borrar los documentos y el proceso de firma.
        /// </summary>
        /// <param name="accessToken">Token de OAuth 2.0</param>
        /// <param name="url">URL del recurso a borrar</param>
        /// <returns></returns>
        internal HttpStatusCode DeleteMethod(string accessToken, string url)
        {
            HttpClient httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
            var response = httpClient.DeleteAsync(url);
            return response.Result.StatusCode;
        }
    }
}