namespace Hims.Infrastructure.Helpers
{
    using System;
    using System.IO;
    using System.Threading.Tasks;
    using Domain.Helpers;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Abstractions;
    using Microsoft.AspNetCore.Mvc.ModelBinding;
    using Microsoft.AspNetCore.Mvc.Razor;
    using Microsoft.AspNetCore.Mvc.Rendering;
    using Microsoft.AspNetCore.Mvc.ViewFeatures;
    using Microsoft.AspNetCore.Routing;

    /// <inheritdoc />
    public class TemplateHelper : ITemplateHelper
    {
        /// <summary>
        /// The view engine.
        /// </summary>
        private readonly IRazorViewEngine viewEngine;

        /// <summary>
        /// The service provider.
        /// </summary>
        private readonly IServiceProvider serviceProvider;

        /// <summary>
        /// The temp data provider.
        /// </summary>
        private readonly ITempDataProvider tempDataProvider;

        /// <summary>
        /// Initializes a new instance of the <see cref="TemplateHelper"/> class.
        /// </summary>
        /// <param name="viewEngine">
        /// The view engine.
        /// </param>
        /// <param name="serviceProvider">
        /// The service provider.
        /// </param>
        /// <param name="tempDataProvider">
        /// The temp data provider.
        /// </param>
        public TemplateHelper(IRazorViewEngine viewEngine, IServiceProvider serviceProvider, ITempDataProvider tempDataProvider)
        {
            this.viewEngine = viewEngine;
            this.serviceProvider = serviceProvider;
            this.tempDataProvider = tempDataProvider;
        }

        /// <inheritdoc />
        public async Task<string> RenderTemplateAsync<TViewModel>(string filename, TViewModel viewModel)
        {
            var httpContext = new DefaultHttpContext
            {
                RequestServices = this.serviceProvider
            };

            var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

            using (var outputWriter = new StringWriter())
            {
                var viewResult = this.viewEngine.FindView(actionContext, filename, false);
                var viewDictionary = new ViewDataDictionary<TViewModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                {
                    Model = viewModel
                };

                var tempDataDictionary = new TempDataDictionary(httpContext, this.tempDataProvider);
                var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, tempDataDictionary, outputWriter, new HtmlHelperOptions());
                await viewResult.View.RenderAsync(viewContext);
                return outputWriter.ToString();
            }
        }
    }
}