using System.Text;
using System.Xml;
using System.Xml.Linq;
using IWS5.Server.Enums;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;

namespace IWS5.Server.Utils.Converter.TiffConverter;

internal class XmlFileToTiffConverter : IFileConverter
{
    private static readonly HashSet<string> Extensions = new(StringComparer.OrdinalIgnoreCase)
    {
        nameof(ConvertibleFileTypes.xml).ToLowerInvariant()
    };

    public bool CanConvert(string sourceFileExtension, string targetFileExtension) => Extensions.Contains(sourceFileExtension) && 
        string.Equals(targetFileExtension, nameof(ConvertibleFileTypes.tiff), StringComparison.OrdinalIgnoreCase);

    public async Task<byte[]> ConvertAsync(byte[] inputFile)
    {
        try
        {
            string xmlContent = Encoding.UTF8.GetString(inputFile);

            if (string.IsNullOrWhiteSpace(xmlContent))
                throw new ArgumentException("XML content cannot be null or empty.");

            string formattedXml = FormatXml(xmlContent);

            // Convert to PDF first
            using var pdfDocument = new PdfDocument();
            PdfPage page = pdfDocument.Pages.Add();
            PdfGraphics graphics = page.Graphics;

            PdfFont font = new PdfStandardFont(PdfFontFamily.Courier, 10);
            PdfSolidBrush brush = new PdfSolidBrush(Syncfusion.Drawing.Color.Black);

            float margin = 40;
            float pageWidth = page.GetClientSize().Width - (2 * margin);
            float yPosition = margin;
            float lineHeight = font.Height + 2;

            string[] lines = formattedXml.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string line in lines)
            {
                if (yPosition + lineHeight > page.GetClientSize().Height - margin)
                {
                    page = pdfDocument.Pages.Add();
                    graphics = page.Graphics;
                    yPosition = margin;
                }

                var textSize = font.MeasureString(line);
                if (textSize.Width > pageWidth)
                {
                    var wrappedLines = WrapText(line, font, pageWidth);
                    foreach (string wrappedLine in wrappedLines)
                    {
                        if (yPosition + lineHeight > page.GetClientSize().Height - margin)
                        {
                            page = pdfDocument.Pages.Add();
                            graphics = page.Graphics;
                            yPosition = margin;
                        }

                        graphics.DrawString(wrappedLine, font, brush, new Syncfusion.Drawing.PointF(margin, yPosition));
                        yPosition += lineHeight;
                    }
                }
                else
                {
                    graphics.DrawString(line, font, brush, new Syncfusion.Drawing.PointF(margin, yPosition));
                    yPosition += lineHeight;
                }
            }

            using var pdfStream = new MemoryStream();
            pdfDocument.Save(pdfStream);
            pdfDocument.Close(true);

            // Use shared PDF to TIFF converter
            return await PdfToTiffConverter.ConvertAsync(pdfStream.ToArray());
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException($"Error converting XML to TIFF: {ex.Message}", ex);
        }
    }

    private static string FormatXml(string xmlContent)
    {
        try
        {
            var doc = XDocument.Parse(xmlContent);
            return doc.ToString();
        }
        catch (XmlException)
        {
            return xmlContent;
        }
    }

    private static List<string> WrapText(string text, PdfFont font, float maxWidth)
    {
        var wrappedLines = new List<string>();
        var words = text.Split(' ');
        var currentLine = new StringBuilder();

        foreach (string word in words)
        {
            string testLine = currentLine.Length == 0 ? word : $"{currentLine} {word}";

            var testSize = font.MeasureString(testLine);
            if (testSize.Width <= maxWidth)
            {
                currentLine.Append(currentLine.Length == 0 ? word : $" {word}");
            }
            else
            {
                if (currentLine.Length > 0)
                {
                    wrappedLines.Add(currentLine.ToString());
                    currentLine.Clear();
                }

                currentLine.Append(word);
            }
        }

        if (currentLine.Length > 0)
        {
            wrappedLines.Add(currentLine.ToString());
        }

        return wrappedLines;
    }
}