using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewEngines;

namespace Yavsc.Helpers
{
    using ViewModels.Gen;
    public class TeXString : HtmlString
    {

        public TeXString(TeXString teXString): base(teXString.ToString())
        {
        }

        public TeXString(string str) : base(str)
        {


        }

        public static TeXString operator+ (TeXString a, TeXString b) {
            return new TeXString(a.ToString()+b.ToString());
        }

    }
    public class Replacement
        {
            string target;
            string replacement;
            public Replacement(string target, string replacement)
            {
                this.target = target;
                this.replacement = replacement;
            }
            public string Execute(string source)
            {
                return source?.Replace(target, replacement) ?? null;
            }
        }
    public static class TeXHelpers
    {
        public static readonly  Replacement[] SpecialCharsDefaultRendering =
        {
            new Replacement("<","\\textless"),
            new Replacement(">","\\textgreater"),
            new Replacement("©","\\copyright"),
            new Replacement("®","\\textregistered"),
            new Replacement("\\","\\textbackslash"),
            new Replacement("™","\\texttrademark"),
            new Replacement("¶","\\P"),
            new Replacement("|","\\textbar"),
            new Replacement("%","\\%"),
            new Replacement("{","\\{"),
            new Replacement("}","\\}"),
            new Replacement("_","\\_"),
            new Replacement("#","\\#"),
            new Replacement("$","\\$"),
            new Replacement("_","\\_"),
            new Replacement("¿","\\textquestiondown"),
            new Replacement("§","\\S"),
            new Replacement("£","\\pounds"),
            new Replacement("&","\\&"),
            new Replacement("¡","\\textexclamdown"),
            new Replacement("†","\\dag"),
            new Replacement("–","\\textendash"),
            new Replacement("°","\\textdegree")
        };

         public static TeXString ToTeX(this string source, string defaultValue="\\textit{néant}")
        {
            if (source==null) return new TeXString(defaultValue);
            string result=source;
            foreach (var r in SpecialCharsDefaultRendering)
            {
                result = r.Execute(result);
            }
            return new TeXString(result);
        }

        public static TeXString ToTeXCell(this string source, string defaultValue="\\textit{néant}")
        {
            if (source==null) return new TeXString(defaultValue);
            string result=source;
            foreach (var r in SpecialCharsDefaultRendering)
            {
                result = r.Execute(result);
            }
            result = result.Replace("\n","\\tabularnewline ");
            return new TeXString(result);
        }
        

        public static string NewLinesWith(this string target, string separator)
        {
            var items = target.Split(new char[] { '\n' }).Where(
                s => !string.IsNullOrWhiteSpace(s));

            return string.Join(separator, items);
        }

        public static TeXString ToTeXLines(this string source, string defaultValue, string lineSeparator = "\n\\\\")
        {
            if (source == null) return new TeXString(defaultValue);
            return new TeXString( source.ToTeX().ToString().NewLinesWith(lineSeparator) );
        }

        public static TeXString SplitAddressToTeX (this string source, string lineSeparator = "\n\\\\", string defaultValue = "\\textit{pas d'adresse postale}")
        {
            if (string.IsNullOrWhiteSpace(source)) return new TeXString(defaultValue);
            var alines = source.Split(',');
            var texlines = alines.Select(l=>l.ToTeX().ToString());
            return new TeXString(string.Join(lineSeparator,texlines));
        }

        public static bool GenerateEstimatePdf(this PdfGenerationViewModel Model)
        {
            string errorMsg = null;
            var billdir = Model.DestDir;
            var tempdir = Startup.SiteSetup.TempDir;
            string name = Model.BaseFileName;
            string fullname = new FileInfo(
                 System.IO.Path.Combine(tempdir, name)).FullName;
            string ofullname = new FileInfo(
                 System.IO.Path.Combine(billdir, name)).FullName;

            FileInfo fi = new FileInfo(fullname + ".tex");
            FileInfo fo = new FileInfo(ofullname + ".pdf");
            using (StreamWriter sw = new StreamWriter(fi.FullName))
            {
                sw.Write(Model.TeXSource);
            }
            if (!fi.Exists)
            {
                errorMsg = "Source write failed";
            }
            else
            {
                using (Process p = new Process())
                {
                    p.StartInfo.WorkingDirectory = tempdir;
                    p.StartInfo = new ProcessStartInfo();
                    p.StartInfo.UseShellExecute = false;
                    p.StartInfo.WorkingDirectory = tempdir;
                    p.StartInfo.FileName = "/usr/bin/texi2pdf";
                    p.StartInfo.Arguments = $"--batch --build-dir=. -o {fo.FullName} {fi.FullName}";
                    p.Start();
                    p.WaitForExit();
                    if (p.ExitCode != 0)
                    {
                        errorMsg = $"Pdf generation failed with exit code: {p.ExitCode}";
                    }
                    else 
                    {
                      fi.Delete();
                      var di = new DirectoryInfo(Path.Combine(tempdir,$"{Model.BaseFileName}.t2d"));
                      di.Delete(true);

                    }
                }
            }
            Model.Generated = fo.Exists;
            Model.GenerationErrorMessage = new HtmlString(errorMsg);
            return fo.Exists;
        }

        public static string RenderViewToString(
            this Controller controller, IViewEngine engine,
            IHttpContextAccessor httpContextAccessor,
         string viewName, object model)
        {
            using (var sw = new StringWriter())
            {
                if (engine == null)
                    throw new InvalidOperationException("no engine");

                // try to find the specified view
                controller.TryValidateModel(model);
                ViewEngineResult viewResult = engine.FindPartialView(controller.ActionContext, viewName);

                // create the associated context
                ViewContext viewContext = new ViewContext();
                viewContext.ActionDescriptor = controller.ActionContext.ActionDescriptor;
                viewContext.HttpContext = controller.ActionContext.HttpContext;
                viewContext.TempData = controller.TempData;
                viewContext.View = viewResult.View;
                viewContext.Writer = sw;

                // write the render view with the given context to the stringwriter
                viewResult.View.RenderAsync(viewContext);
                viewResult.EnsureSuccessful();
                return sw.GetStringBuilder().ToString();
            }
        }
    }
}
