using Azure.Storage.Blobs; // BlobContainerClient
using Azure.Storage.Blobs.Models; // BlobContainerInfo
using Azure.Storage.Queues.Models; // QueueMessage
using Microsoft.Azure.WebJobs; // [FunctionName], [QueueTrigger]
using Microsoft.Extensions.Logging; // ILogger
using SixLabors.Fonts; // Font
using SixLabors.ImageSharp; // Image
using SixLabors.ImageSharp.Drawing; // IPath
using SixLabors.ImageSharp.Drawing.Processing; // IBrush, IPen
using SixLabors.ImageSharp.PixelFormats; // PixelColorBlendingMode
using SixLabors.ImageSharp.Processing; // Metoda rozszerzająca Mutate.
using System.IO; // Stream, FileAccess
using System.Threading.Tasks; // Task<T>

namespace Northwind.AzureFunctions.Service;

[StorageAccount("AzureWebJobsStorage")]
public static class CheckGeneratorFunction
{
  [FunctionName(nameof(CheckGeneratorFunction))]
  public static async Task Run(
    [QueueTrigger("checksQueue")] QueueMessage message,
    [Blob("checks-blob-container")] BlobContainerClient blobContainerClient,
    ILogger log)
  {
    // Zapisanie w dzienniku pewnych informacji o komunikacie.
    log.LogInformation("Wywołana funkcja C# wyzwalacza Queue.");
    log.LogInformation($"Identyfikator komunikatu: {message.MessageId}.");
    log.LogInformation($"Czas umieszczenia: {message.InsertedOn}.");
    log.LogInformation($"Czas wygaśnięcia: {message.ExpiresOn}.");
    log.LogInformation($"Treść: {message.Body}.");

    // Utworzenie pustego obrazu z białym tłem.
    using (Image<Rgba32> image = new(width: 1200, height: 600,
      backgroundColor: new Rgba32(r: 255, g: 255, b: 255, a: 100)))
    {
      // Załadowanie pliku i utworzenie dużej czcionki.
      FontCollection collection = new();
      FontFamily family = collection.Add(
        @"fonts\Caveat\static\Caveat-Regular.ttf");
      Font font = family.CreateFont(72);

      string amount = message.Body.ToString();

      DrawingOptions options = new()
      {
        GraphicsOptions = new()
        {
          ColorBlendingMode = PixelColorBlendingMode.Multiply
        }
      };

      // Zdefiniowanie piór i pędzli.

      IPen blackPen = Pens.Solid(Color.Black, 2);
      IPen blackThickPen = Pens.Solid(Color.Black, 8);
      IPen greenPen = Pens.Solid(Color.Green, 3);
      IBrush redBrush = Brushes.Solid(Color.Red);
      IBrush blueBrush = Brushes.Solid(Color.Blue);

      // Zdefiniowanie i narysowanie ścieżek.

      IPath border = new RectangularPolygon(
        x: 50, y: 50, width: 1100, height: 500);

      image.Mutate(x => x.Draw(options, blackPen, border));

      IPath star = new Star(x: 150.0f, y: 150.0f, 
        prongs: 5, innerRadii: 20.0f, outerRadii: 30.0f);

      image.Mutate(x => x.Fill(options, redBrush, star)
                         .Draw(options, greenPen, star));

      IPath line1 = new Polygon(new LinearLineSegment(
        new PointF(x: 100, y: 275), new PointF(x: 1050, y: 275)));
      
      image.Mutate(x => x.Draw(options, blackPen, line1));

      IPath line2 = new Polygon(new LinearLineSegment(
        new PointF(x: 100, y: 365), new PointF(x: 1050, y: 365)));

      image.Mutate(x => x.Draw(options, blackPen, line2));

      TextOptions textOptions = new(font)
      {
        Origin = new PointF(100, 200),
        WrappingLength = 1000,
        HorizontalAlignment = HorizontalAlignment.Left
      };

      image.Mutate(x => x.DrawText(
        textOptions, amount, blueBrush, blackPen));

      string blobName = $"{System.DateTime.UtcNow:yyyy-MM-dd-hh-mm-ss}.png";
      log.LogInformation($"Nazwa obiektu BLOB: {blobName}.");

      try
      {
        if (System.Environment.GetEnvironmentVariable("IS_LOCAL") == "true")
        {
          // Utworzenie obiektu BLOB w lokalnym systemie plików.

          string folder = $@"{System.Environment.CurrentDirectory}\blobs";
          if (!Directory.Exists(folder))
          {
            Directory.CreateDirectory(folder);
          }
          log.LogInformation($"Katalog obiektów BLOB: {folder}");

          string blobPath = $@"{folder}\{blobName}";

          await image.SaveAsPngAsync(blobPath);
        }

        // Utworzenie obiektu BLOB w magazynie z użyciem strumienia pamięci.

        Stream stream = new MemoryStream();

        await image.SaveAsPngAsync(stream);

        stream.Seek(0, SeekOrigin.Begin);

        blobContainerClient.CreateIfNotExists();

        BlobContentInfo info = await blobContainerClient.UploadBlobAsync(
          blobName, stream);

        log.LogInformation(
          $"Numer sekwencyjny obiektu BLOB: {info.BlobSequenceNumber}.");
      }
      catch (System.Exception ex)
      {
        log.LogError(ex.Message);
      }
    }
  }
}
