using ImageMagick;
using Ocr.Tesseract.Configuration;
using Ocr.Tesseract.Extensions;
using Ocr.Tesseract.Models;
using Process.Abstract;
using System.Collections.Generic;
using System.Linq;
using Tesseract;

namespace Ocr.Tesseract;

/// <summary>
/// Scans <see cref="MagickImage"/>s for <see cref="Word"/>s
/// and maps the results to a <see cref="ScanResult"/>
/// </summary>
public class TesseractProcessor : Processor<MagickImage, ScanResult>
{
  /// <inheritdoc cref="ITesseractConfiguration"/>
  public ITesseractConfiguration Configuration { get; }

  /// <inheritdoc />
  public TesseractProcessor(ITesseractConfiguration config)
  {
    Configuration = config;
  }

  /// <summary>
  /// Scans the provided <paramref name="image"/> for <see cref="Word"/>s
  /// </summary>
  /// <param name="image">The <see cref="MagickImage"/> to scan</param>
  /// <returns>
  /// A list of <see cref="Word"/>s found
  /// in the provided <paramref name="image"/>
  /// </returns>
  private IEnumerable<Word> Scan(MagickImage image)
  {
    // Convert image
    using var pix = PixConverter.ToPix(image.ToBitmapWithDensity());
    using var engine = new TesseractEngine(
      Configuration.DataPath,
      string.Join('+', Configuration.Languages),
      EngineMode.Default,
      Enumerable.Empty<string>(),
      Configuration.Variables,
      false
    )
    {
      DefaultPageSegMode = PageSegMode.AutoOsd
    };

    // Scan
    return engine
      .Process(pix)
      .GetWords()
      .ToArray();
  }

  /// <inheritdoc />
  public override IEnumerable<ScanResult> Process(
    IEnumerable<MagickImage> inputs
  )
  {
    return inputs
      .SelectMany(Scan, (input, word) => new ScanResult(word, input));
  }
}