using System;
using System.Drawing;
using System.IO;
using System.Text;
using FastReport.Utils;
using FastReport.Export;
using System.Drawing.Imaging;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;

using static FastReport.Web.Blazor.Export.BlazorConstants;

namespace FastReport.Web.Blazor.Export
{
    public partial class BlazorExport
    {
        private void HTMLFontStyle(StringBuilder FFontDesc, Font font, float LineHeight)
        {
            FFontDesc.Append((((font.Style & FontStyle.Bold) > 0) ? "font-weight:bold;" : String.Empty) +
                (((font.Style & FontStyle.Italic) > 0) ? "font-style:italic;" : "font-style:normal;"));
            if ((font.Style & FontStyle.Underline) > 0 && (font.Style & FontStyle.Strikeout) > 0)
                FFontDesc.Append("text-decoration:underline|line-through;");
            else if ((font.Style & FontStyle.Underline) > 0)
                FFontDesc.Append("text-decoration:underline;");
            else if ((font.Style & FontStyle.Strikeout) > 0)
                FFontDesc.Append("text-decoration:line-through;");
            FFontDesc.Append("font-family:").Append(font.Name).Append(';');
            FFontDesc.Append("font-size:").Append(Px(Math.Round(font.Size * 96 / 72))).Append("px;");
            if (LineHeight > 0)
                FFontDesc.Append("line-height:").Append(Px(LineHeight)).Append("px;");
            else
                FFontDesc.Append("line-height: 1.2;");
        }

        private string HTMLBorderStyle(BorderLine line)
        {
            switch (line.Style)
            {
                case LineStyle.Dash:
                case LineStyle.DashDot:
                case LineStyle.DashDotDot:
                    return "dashed";
                case LineStyle.Dot:
                    return "dotted";
                case LineStyle.Double:
                    return "double";
                default:
                    return "solid";
            }
        }

        private float HTMLBorderWidth(BorderLine line)
        {
            if (line.Style == LineStyle.Double)
                return (line.Width * 3 * Zoom);
            else
                return line.Width * Zoom;
        }

        private string HTMLBorderWidthPx(BorderLine line)
        {
            if (line.Style != LineStyle.Double && line.Width == 1 && Zoom == 1)
                return "1px;";
            float width;
            if (line.Style == LineStyle.Double)
                width = line.Width * 3 * Zoom;
            else
                width = line.Width * Zoom;
            return ExportUtils.FloatToString(width) + "px;";
        }

        private void HTMLBorder(StringBuilder BorderDesc, Border border)
        {
            if (border.Lines > 0)
            {
                // bottom
                if ((border.Lines & BorderLines.Bottom) > 0)
                    BorderDesc.Append("border-bottom-width:").
                        Append(HTMLBorderWidthPx(border.BottomLine)).
                        Append("border-bottom-color:").
                        Append(HTMLColor(border.BottomLine.Color)).Append(";border-bottom-style:").
                        Append(HTMLBorderStyle(border.BottomLine)).Append(';');
                else
                    BorderDesc.Append("border-bottom:none;");
                // top
                if ((border.Lines & BorderLines.Top) > 0)
                    BorderDesc.Append("border-top-width:").
                        Append(HTMLBorderWidthPx(border.TopLine)).
                        Append("border-top-color:").
                        Append(HTMLColor(border.TopLine.Color)).Append(";border-top-style:").
                        Append(HTMLBorderStyle(border.TopLine)).Append(';');
                else
                    BorderDesc.Append("border-top:none;");
                // left
                if ((border.Lines & BorderLines.Left) > 0)
                    BorderDesc.Append("border-left-width:").
                        Append(HTMLBorderWidthPx(border.LeftLine)).
                        Append("border-left-color:").
                        Append(HTMLColor(border.LeftLine.Color)).Append(";border-left-style:").
                        Append(HTMLBorderStyle(border.LeftLine)).Append(';');
                else
                    BorderDesc.Append("border-left:none;");
                // right
                if ((border.Lines & BorderLines.Right) > 0)
                    BorderDesc.Append("border-right-width:").
                        Append(HTMLBorderWidthPx(border.RightLine)).
                        Append("border-right-color:").
                        Append(HTMLColor(border.RightLine.Color)).Append(";border-right-style:").
                        Append(HTMLBorderStyle(border.RightLine)).Append(';');
                else
                    BorderDesc.Append("border-right:none;");
            }
            else
                BorderDesc.Append("border:none;");
        }

        private bool HTMLBorderWidthValues(ReportComponentBase obj, out float left, out float top, out float right, out float bottom)
        {
            Border border = obj.Border;
            left = 0;
            top = 0;
            right = 0;
            bottom = 0;

            if (border.Lines > 0)
            {
                if ((border.Lines & BorderLines.Left) > 0)
                    left += HTMLBorderWidth(border.LeftLine);

                if ((border.Lines & BorderLines.Right) > 0)
                    right += HTMLBorderWidth(border.RightLine);

                if ((border.Lines & BorderLines.Top) > 0)
                    top += HTMLBorderWidth(border.TopLine);

                if ((border.Lines & BorderLines.Bottom) > 0)
                    bottom += HTMLBorderWidth(border.BottomLine);

                return true;
            }

            return false;
        }

        private void HTMLGetStylesHeader()
        {
            if (singlePage && pageBreaks)
            {
                var context = globalContext;

                StringBuilder header = new StringBuilder(256);
                context.OpenElement(STYLE);
                context.AddAttribute(TYPE, "text/css");
                context.AddAttribute(MEDIA, "print");

                header.AppendLine("<!--");
                header.Append($"div.").Append(pageStyleName).
                    Append(" { page-break-after: always; page-break-inside: avoid; ");
                if (d.page.Landscape)
                {
                    header.Append("width:").Append(Px(maxHeight * Zoom)).Append(" !important;")
                            .Append("transform: rotate(90deg); -webkit-transform: rotate(90deg)");
                }

                header.AppendLine("}")
                        .AppendLine("-->");
                context.AddContent(header.ToString());
                context.CloseElement();
            }
        }

        private StringBuilder HTMLGetStyleHeader(int index)
        {
            StringBuilder header = new StringBuilder(32);
            return header.Append('.').
                Append(GetStyleTag(index)).
                Append(" { ");
        }

        private RenderFragment HTMLGetAncor(int ancorName)
        {
            return builder =>
            {
                var context = new RenderContext(builder);
                context.OpenElement(A);
                context.AddAttribute(NAME, $"PageN{ancorName}");
                context.AddAttribute(STYLE, "padding:0;margin:0;font-size:1px");
                context.CloseElement();
            };
        }

        private string HTMLGetImage(int CurrentPage, string hash, 
            MemoryStream PictureStream, bool isSvg)
        {
            if (pictures)
            {
                ImageFormat format = ImageFormat.Bmp;
                if (imageFormat == ImageFormat.Png)
                    format = ImageFormat.Png;
                else if (imageFormat == ImageFormat.Jpeg)
                    format = ImageFormat.Jpeg;
                else if (imageFormat == ImageFormat.Gif)
                    format = ImageFormat.Gif;

                string embedImgType = isSvg ? "svg+xml" : format.ToString();
                string embedPreffix = "data:image/" + embedImgType + ";base64,";

                if (EmbedPictures)
                {
                    return embedPreffix + GetBase64Image(PictureStream, hash); 
                }
                else
                {
                    PreparedPages[CurrentPage].Pictures.Add(PictureStream);
                    PreparedPages[CurrentPage].Guids.Add(hash);
                    return WebImagePrefix + "=" + hash + WebImageSuffix;
                }
            }
            else
                return String.Empty;
        }

        private string GetBase64Image(MemoryStream PictureStream, string hash)
        {
            string base64Image;
            if (!EmbeddedImages.TryGetValue(hash, out base64Image))
            {
                base64Image = Convert.ToBase64String(PictureStream.ToArray());
                EmbeddedImages.Add(hash, base64Image);
            }
            return base64Image;
        }
    }
}
