using ImageMagick;
using PosterMaker.Interfaces.Services;
using PosterMaker.Models;
using PosterMaker.Models.Enums;

namespace PosterMaker.Services;

public class MoviePosterMakerService : IMoviePosterMakerService
{
    private static readonly string RefDir = Path.Combine("Resources", "Movies");
    private static readonly string RefDirectory = Path.Combine(Directory.GetCurrentDirectory(), RefDir);
    private static readonly string Font = Path.Combine(RefDirectory, "Arial Bold.ttf");
    private static readonly string Frame = Path.Combine(RefDirectory, "frame.png");
    private static readonly string Gradient = Path.Combine(RefDirectory, "gradient.png");
    
    private const string FontColor = "white";
    private const float FontSize = 1.0F;
    private const string IndexFontColor = "rgb(154,154,154)";

    private readonly IMovieLogoService _movieLogoService;

    public MoviePosterMakerService(IMovieLogoService movieLogoService)
    {
        _movieLogoService = movieLogoService;
    }
    
    public byte[] CreatePoster(string file, ImageProperties imageProperties)
    {
        using var image = new MagickImage(file);
        var resizeGeometry = new MagickGeometry(1892, 2892)
        {
            FillArea = true
        };
        image.Resize(resizeGeometry);
        image.Extent(2000, 3000, Gravity.Center);

        ApplyGradient(image);

        using var frame = new MagickImage(Frame);
        frame.BackgroundColor = new MagickColor("transparent");
        image.Composite(frame, Gravity.Center, CompositeOperator.Over);
        
        AddLogo(image, imageProperties.Logo, imageProperties.LogoOption);
        AddIndex(image, imageProperties.Index);
        AddTitle(image, imageProperties);
        
        return image.ToByteArray();
    }

    private static void ApplyGradient(MagickImage image)
    {
        using var gradient = new MagickImage(Gradient);
        image.Composite(gradient, Gravity.Center, CompositeOperator.Multiply);
    }

    private static void AddIndex(MagickImage image, string? input)
    {
        if (string.IsNullOrEmpty(input)) return;
        var readSettings = new MagickReadSettings
        {
            Font = Font,
            FillColor = new MagickColor(IndexFontColor),
            FontPointsize = 598,
            TextGravity = Gravity.Center,
            BackgroundColor = MagickColors.Transparent,
        };
        var index = new MagickImage($"label:{(input)}", readSettings);
        image.Composite(index, Gravity.South, 0, 50, CompositeOperator.Atop);
    }

    private void AddLogo(MagickImage image, MovieLogoEnum? logo, LogoOptionEnum? logoOptionEnum)
    {
        if (logo == null) return;
        var logoFile = _movieLogoService.GetMovieLogo(logo);
        var gravity = _movieLogoService.GetLogoGravity(logo);
        var readSettings = new MagickReadSettings
        {
            TextGravity = Gravity.Center,
            BackgroundColor = MagickColors.Transparent
        };
        using var logoImage = new MagickImage(logoFile, readSettings);
        logoImage.Resize(_movieLogoService.GetLogoGeometry(logo));

        if (logoOptionEnum == LogoOptionEnum.White)
        {
            logoImage.Colorize(MagickColors.White, new Percentage(100));
        }
        if (logoOptionEnum == LogoOptionEnum.Black)
        {
            logoImage.Colorize(MagickColors.Black, new Percentage(100));
        }
        var shadow = new MagickImage(logoImage);
        shadow.Shadow(3, 3,3, new Percentage(80));
        var offset = gravity == Gravity.Northwest ? 100 : 0;
        image.Composite(shadow, gravity, offset, 100, CompositeOperator.Atop);
        
        image.Composite(logoImage, gravity, offset, 100, CompositeOperator.Atop);
    }

    private void AddTitle(MagickImage image, ImageProperties properties)
    {
        if (string.IsNullOrEmpty(properties.TopSubtitle) && string.IsNullOrEmpty(properties.Title) && string.IsNullOrEmpty(properties.Subtitle))
            return;

        var readSettings = new MagickReadSettings
        {
            BackgroundColor = MagickColors.Transparent,
            FillColor = new MagickColor(FontColor),
            Font = Font,
            Debug = true
        };

        var labelImages = new MagickImageCollection();
        if (!string.IsNullOrEmpty(properties.TopSubtitle))
        {
            readSettings.FontPointsize = 95 * FontSize;
            readSettings.TextGravity = Gravity.Center;
            labelImages.Add(new MagickImage($"label:{properties.TopSubtitle.ToUpper()}", readSettings));

        }

        if (!string.IsNullOrEmpty(properties.Title))
        {
            readSettings.FontPointsize = 190 * FontSize;
            readSettings.TextKerning = 0.7;
            readSettings.TextInterlineSpacing = -44.5;
            readSettings.TextInterwordSpacing = 55;
            readSettings.TextGravity = Gravity.Center;
            labelImages.Add(new MagickImage($"label:{properties.Title.ToUpper()}", readSettings));
        }
        if (!string.IsNullOrEmpty(properties.Title2))
        {
            readSettings.FontPointsize = 190 * FontSize;
            readSettings.TextKerning = 0.7;
            readSettings.TextInterlineSpacing = -44.5;
            readSettings.TextInterwordSpacing = 55;
            readSettings.TextGravity = Gravity.Center;
            labelImages.Add(new MagickImage($"label:{properties.Title2.ToUpper()}", readSettings));
        }

        if (!string.IsNullOrEmpty(properties.Subtitle))
        {
            readSettings.FontPointsize = 95 * FontSize;
            readSettings.TextInterwordSpacing = 18;
            readSettings.TextKerning = 0.5;
            readSettings.TextGravity = Gravity.Center;
            labelImages.Add(new MagickImage($"label:{properties.Subtitle.ToUpper()}", readSettings));
        }

        using var labels = labelImages.SmushVertical(30);
        var titleHeight = !string.IsNullOrEmpty(properties.Subtitle) ? 182 : 262;
        image.Composite(labels, Gravity.South, 0, titleHeight, CompositeOperator.Atop);
    }
}