using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace SelectPdf.AzureFunctions.Sample
{
    public static class ConvertToPdf
    {
        /// <summary>
        /// Use this function to convert an url or html to pdf using SelectPdf. 
        /// The function shows how you can send a few parameters 
        /// through GET or POST (x-www-form-urlencoded or json encoded).
        /// Send at least the "url" or "html" parameter.
        /// Other parameters are also supported (see code).
        /// </summary>
        /// <returns></returns>
        [FunctionName("ConvertToPdf")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("Starting the conversion to pdf...");

            try
            {
                // read parameters from query string
                string url = req.Query["url"];
                string html = req.Query["html"];
                string base_url = req.Query["base_url"];
                string page_size = req.Query["page_size"];
                string page_orientation = req.Query["page_orientation"];
                string web_page_width_str = req.Query["web_page_width"];
                string web_page_height_str = req.Query["web_page_height"];
                string rendering_engine = req.Query["rendering_engine"];

                // read from POST if encoding is application/x-www-form-urlencoded
                if (req.ContentType?.ToLower() == "application/x-www-form-urlencoded")
                {
                    url = url ?? req.Form["url"];
                    html = html ?? req.Form["html"];
                    base_url = base_url ?? req.Form["base_url"];
                    page_size = page_size ?? req.Form["page_size"];
                    page_orientation = page_orientation ?? req.Form["page_orientation"];
                    web_page_width_str = web_page_width_str ?? req.Form["web_page_width"];
                    web_page_height_str = web_page_height_str ?? req.Form["web_page_height"];
                    rendering_engine = rendering_engine ?? req.Form["rendering_engine"];
                }
                // read from POST if encoding is application/json
                else if (req.ContentType?.ToLower() == "application/json")
                {
                    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                    dynamic postData = JsonConvert.DeserializeObject(requestBody);

                    url = url ?? postData?.url;
                    html = html ?? postData?.html;
                    base_url = base_url ?? postData?.base_url;
                    page_size = page_size ?? postData?.page_size;
                    page_orientation = page_orientation ?? postData?.page_orientation;
                    web_page_width_str = web_page_width_str ?? postData?.web_page_width;
                    web_page_height_str = web_page_height_str ?? postData?.web_page_height;
                    rendering_engine = rendering_engine ?? (string)postData?.rendering_engine;
                }

                // parse parameters
                log.LogInformation("Parsed url: " + url?.ToString());
                log.LogInformation("Parsed html: " + html?.ToString());
                log.LogInformation("Parsed base_url: " + base_url?.ToString());

                int web_page_width = 1024;
                if (!string.IsNullOrEmpty(web_page_width_str))
                {
                    try
                    {
                        web_page_width = Convert.ToInt32(web_page_width_str);
                    }
                    catch { }
                }
                log.LogInformation("Parsed web_page_width: " + web_page_width);

                int web_page_height = 0;
                if (!string.IsNullOrEmpty(web_page_height_str))
                {
                    try
                    {
                        web_page_height = Convert.ToInt32(web_page_height_str);
                    }
                    catch { }
                }
                log.LogInformation("Parsed web_page_height: " + web_page_height);

                // pdf page size
                PdfPageSize pageSize = PdfPageSize.A4;
                try
                {
                    pageSize = (PdfPageSize)Enum.Parse(typeof(PdfPageSize), page_size, true);
                }
                catch { }
                log.LogInformation("Parsed page_size: " + pageSize.ToString());

                // pdf orientation
                PdfPageOrientation pdfOrientation = PdfPageOrientation.Portrait;
                try
                {
                    pdfOrientation = (PdfPageOrientation)Enum.Parse(
                        typeof(PdfPageOrientation), page_orientation, true);
                }
                catch { }
                log.LogInformation("Parsed page_orientation: " + pdfOrientation.ToString());

                // rendering engine (WebKit / WebKitRestricted / Blink / Chromium)
                SelectPdf.RenderingEngine renderingEngine = SelectPdf.RenderingEngine.Chromium;
                try
                {
                    renderingEngine = (SelectPdf.RenderingEngine)Enum.Parse(
                        typeof(SelectPdf.RenderingEngine), rendering_engine, true);
                }
                catch { }
                log.LogInformation("Parsed rendering_engine: " + renderingEngine.ToString());


                // check for mandatory parameters
                if (string.IsNullOrEmpty(url) && string.IsNullOrEmpty(html))
                {
                    string responseMessage = "Url or html string not specified.";
                    return new BadRequestObjectResult(responseMessage);
                }

                // instantiate converter object
                SelectPdf.HtmlToPdf converter = new SelectPdf.HtmlToPdf();

                // set converter options
                converter.Options.RenderingEngine = renderingEngine;
                converter.Options.WebPageWidth = web_page_width;
                converter.Options.WebPageHeight = web_page_height;

                converter.Options.PdfPageSize = pageSize;
                converter.Options.PdfPageOrientation = pdfOrientation;

                SelectPdf.PdfDocument doc;

                // convert url or html string to pdf
                if (!string.IsNullOrEmpty(url))
                {
                    doc = converter.ConvertUrl(url);
                }
                else
                {
                    doc = converter.ConvertHtmlString(html, base_url);
                }

                // save pdf
                byte[] pdf = doc.Save();
                doc.Close();

                log.LogInformation("Conversion finished. Returning file...");

                return new FileContentResult(pdf, "application/pdf")
                {
                    FileDownloadName = "Document.pdf"
                };
            }
            catch (Exception ex)
            {
                string responseMessage = "An error occured: " + 
                    ex.Message + "\r\n" + ex.StackTrace;
                return new BadRequestObjectResult(responseMessage);
            }
        }
    }
}
