using DlibDotNet;
using DlibDotNet.Extensions;
using System.Drawing;
using View_by_Distance.Shared.Models.Stateless;

namespace View_by_Distance.FaceRecognitionDotNet;

/// <summary>
/// Represents a image data. This class cannot be inherited.
/// </summary>
public sealed class Image : DisposableObject
{

    #region Fields

    #endregion

    #region Constructors

    internal Image(MatrixBase matrix, Mode mode)
    {
        Matrix = matrix;
        Mode = mode;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets the height of the image.
    /// </summary>
    /// <exception cref="ObjectDisposedException">This object is disposed.</exception>
    public int Height
    {
        get
        {
            ThrowIfDisposed();
            return Matrix.Rows;
        }
    }

    internal MatrixBase Matrix { get; private set; }

    internal Mode Mode { get; }

    /// <summary>
    /// Gets the width of the image.
    /// </summary>
    /// <exception cref="ObjectDisposedException">This object is disposed.</exception>
    public int Width
    {
        get
        {
            ThrowIfDisposed();
            return Matrix.Columns;
        }
    }

    #endregion

    #region Methods

    /// <summary>
    /// Saves this <see cref="Image"/> to the specified file.
    /// </summary>
    /// <param name="fileName">A string that contains the name of the file to which to save this <see cref="Image"/>.</param>
    /// <param name="format">The <see cref="ImageFormat"/> for this <see cref="Image"/>.</param>
    /// <exception cref="NullReferenceException"><paramref name="fileName"/> is null.</exception>
    /// <exception cref="ObjectDisposedException">This object is disposed.</exception>
    public void Save(string fileName, ImageFormat format)
    {
        if (fileName == null)
            throw new NullReferenceException(nameof(fileName));

        ThrowIfDisposed();

        string? directory = Path.GetDirectoryName(fileName);
        if (!Directory.Exists(directory) && !string.IsNullOrWhiteSpace(directory))
            _ = Directory.CreateDirectory(directory);

        switch (format)
        {
            case ImageFormat.Bmp:
                DlibDotNet.Dlib.SaveBmp(Matrix, fileName);
                break;
            case ImageFormat.Jpeg:
                DlibDotNet.Dlib.SaveJpeg(Matrix, fileName);
                break;
            case ImageFormat.Png:
                DlibDotNet.Dlib.SavePng(Matrix, fileName);
                break;
        }
    }

    /// <summary>
    /// Converts this <see cref="Image"/> to a GDI+ <see cref="Bitmap"/>.
    /// </summary>
    /// <returns>A <see cref="Bitmap"/> that represents the converted <see cref="Image"/>.</returns>
    /// <exception cref="ObjectDisposedException">This object is disposed.</exception>
    /// <exception cref="NotSupportedException">A Greyscale image is not supported.</exception>
    public Bitmap ToBitmap()
    {
        ThrowIfDisposed();

        if (Mode == Mode.Greyscale)
            throw new NotSupportedException();

        return ((Matrix<RgbPixel>)Matrix).ToBitmap();
    }

    #region Overrides 

    /// <summary>
    /// Releases all unmanaged resources.
    /// </summary>
    protected override void DisposeUnmanaged()
    {
        base.DisposeUnmanaged();
        Matrix?.Dispose();
    }

    #endregion

    #endregion

}