using System;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.Processing;

namespace ImageProvider.Extensions {
  internal static class IImageProcessingContextExtensions {
    internal static IImageProcessingContext ApplyScalingWaterMark(this IImageProcessingContext processingContext, Font font, string text, Color color, float padding, bool wordwrap) {
      if (wordwrap) {
        return processingContext.ApplyScalingWaterMarkWordWrap(font, text, color, padding);
      }
      else {
        return processingContext.ApplyScalingWaterMarkSimple(font, text, color, padding);
      }
    }

    internal static IImageProcessingContext ApplyScalingWaterMarkSimple(this IImageProcessingContext processingContext,
        Font font,
        string text,
        Color color,
        float padding) {
      Size imgSize = processingContext.GetCurrentSize();

      float targetWidth = imgSize.Width - (padding * 2);
      float targetHeight = imgSize.Height - (padding * 2);

      // measure the text size
      FontRectangle size = TextMeasurer.Measure(text, new RendererOptions(font));

      //find out how much we need to scale the text to fill the space (up or down)
      float scalingFactor = Math.Min(imgSize.Width / size.Width, imgSize.Height / size.Height);

      //create a new font
      Font scaledFont = new Font(font, scalingFactor * font.Size);

      var center = new PointF(imgSize.Width / 2, imgSize.Height / 2);
      var textGraphicOptions = new TextGraphicsOptions() {
        TextOptions = {
                    HorizontalAlignment = HorizontalAlignment.Center,
                    VerticalAlignment = VerticalAlignment.Center
                }
      };
      return processingContext.DrawText(textGraphicOptions, text, scaledFont, color, center);
    }

    internal static IImageProcessingContext ApplyScalingWaterMarkWordWrap(this IImageProcessingContext processingContext,
        Font font,
        string text,
        Color color,
        float padding) {
      Size imgSize = processingContext.GetCurrentSize();
      float targetWidth = imgSize.Width - (padding * 2);
      float targetHeight = imgSize.Height - (padding * 2);

      float targetMinHeight = imgSize.Height - (padding * 3); // must be with in a margin width of the target height

      // now we are working i 2 dimensions at once and can't just scale because it will cause the text to
      // reflow we need to just try multiple times

      var scaledFont = font;
      FontRectangle s = new FontRectangle(0, 0, float.MaxValue, float.MaxValue);

      float scaleFactor = (scaledFont.Size / 2); // every time we change direction we half this size
      int trapCount = (int)scaledFont.Size * 2;
      if (trapCount < 10) {
        trapCount = 10;
      }

      bool isTooSmall = false;

      while ((s.Height > targetHeight || s.Height < targetMinHeight) && trapCount > 0) {
        if (s.Height > targetHeight) {
          if (isTooSmall) {
            scaleFactor = scaleFactor / 2;
          }

          scaledFont = new Font(scaledFont, scaledFont.Size - scaleFactor);
          isTooSmall = false;
        }

        if (s.Height < targetMinHeight) {
          if (!isTooSmall) {
            scaleFactor = scaleFactor / 2;
          }
          scaledFont = new Font(scaledFont, scaledFont.Size + scaleFactor);
          isTooSmall = true;
        }
        trapCount--;

        s = TextMeasurer.Measure(text, new RendererOptions(scaledFont) {
          WrappingWidth = targetWidth
        });
      }

      var center = new PointF(padding, imgSize.Height / 2);
      var textGraphicOptions = new TextGraphicsOptions() {
        TextOptions = {
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center,
                    WrapTextWidth = targetWidth
                }
      };
      return processingContext.DrawText(textGraphicOptions, text, scaledFont, color, center);
    }
  }
}
