using System.Diagnostics;
using SkiaSharp;
using SkiaSharp.Views.Maui;

namespace ex_OutlineText.Views;

public partial class LabelOutline : ContentView
{
	public LabelOutline()
	{
		InitializeComponent();
	}

	public static readonly BindableProperty TextProperty 
        = BindableProperty.Create(nameof(Text), 
                                  typeof(string),
                                  typeof(LabelOutline),
                                  "something",
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
	}

	public static readonly BindableProperty FillProperty 
        = BindableProperty.Create(nameof(Fill), 
                                  typeof(Color),
                                  typeof(LabelOutline),
                                  Colors.DarkSalmon,
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());
								  

    public Color Fill
    {
        get { return (Color)GetValue(FillProperty); }
        set { SetValue(FillProperty, value); }
	}

	public static readonly BindableProperty StrokeProperty 
        = BindableProperty.Create(nameof(Stroke), 
                                  typeof(Color),
                                  typeof(LabelOutline),
                                  Colors.DarkSalmon,
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());

    public Color Stroke
    {
        get { return (Color)GetValue(StrokeProperty); }
        set { SetValue(StrokeProperty, value); }
	}

	public static readonly BindableProperty StrokeWidthProperty 
        = BindableProperty.Create(nameof(StrokeWidth), 
                                  typeof(float),
                                  typeof(LabelOutline),
                                  1.0f,
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());

    public float StrokeWidth
    {
        get { return (float)GetValue(StrokeWidthProperty); }
        set { SetValue(StrokeWidthProperty, value); }
	}

	public static readonly BindableProperty FontFamilyProperty 
        = BindableProperty.Create(nameof(FontFamily), 
                                  typeof(string),
                                  typeof(LabelOutline),
                                  "something",
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());

    public string FontFamily
    {
        get { return (string)GetValue(FontFamilyProperty); }
        set { SetValue(FontFamilyProperty, value); }
	}

	public static readonly BindableProperty TextSizeProperty 
        = BindableProperty.Create(nameof(TextSize), 
                                  typeof(float),
                                  typeof(LabelOutline),
                                  24.0f,
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());

    public float TextSize
    {
        get { return (float)GetValue(TextSizeProperty); }
        set { SetValue(TextSizeProperty, value); }
	}

	public static readonly BindableProperty AspectProperty 
        = BindableProperty.Create(nameof(Aspect), 
                                  typeof(Aspect),
                                  typeof(LabelOutline),
                                  Aspect.Center,
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());

	public Aspect Aspect
    {
        get { return (Aspect)GetValue(AspectProperty); }
        set { SetValue(AspectProperty, value); }
	}

	public static readonly BindableProperty RatioProperty 
        = BindableProperty.Create(nameof(Ratio), 
                                  typeof(float),
                                  typeof(LabelOutline),
                                  0.95f,
								  propertyChanged: (b, ov, nv) => (b as LabelOutline)?.canvasView.InvalidateSurface());

    public float Ratio
    {
        get { return (float)GetValue(RatioProperty); }
        set { SetValue(RatioProperty, value); }
	}

	private void OnPainting(object sender, SKPaintSurfaceEventArgs args)
	{
		SKImageInfo info = args.Info;
		SKCanvas canvas = args.Surface.Canvas;

		canvas.Clear();

		// Create an SKPaint object to display the text
		SKPaint textPaint = new SKPaint
		{
			Style = SKPaintStyle.Fill,
			StrokeWidth = StrokeWidth,
			FakeBoldText = true,
			Typeface = SKTypeface.FromFamilyName(FontFamily),
			Color = Fill.ToSKColor(),
			TextSize = TextSize
		};

		switch(Aspect)
		{
			case Aspect.AspectFit:
				float textHeight = Ratio * info.Height;
				float textWidth2 = textPaint.MeasureText(Text);
				textWidth2 = Ratio * info.Width * textPaint.TextSize / textWidth2;
				textPaint.TextSize = Math.Min(textHeight, textWidth2);
				break;
			case Aspect.AspectFill:
			case Aspect.Fill:
				float textWidth = textPaint.MeasureText(Text);
				textPaint.TextSize = Ratio * info.Width * textPaint.TextSize / textWidth;
				break;
			case Aspect.Center:
			default:
				break;
		}

		// Find the text bounds
		SKRect textBounds = new SKRect();
		textPaint.MeasureText(Text, ref textBounds);

		// Calculate offsets to center the text on the screen
		float xText = info.Width / 2 - textBounds.MidX;
		float yText = info.Height / 2 - textBounds.MidY;

		// And draw the text
		canvas.DrawText(Text, xText, yText, textPaint);

		if(StrokeWidth > 0.0f)
		{
			textPaint.Style = SKPaintStyle.Stroke;
			textPaint.Color = Stroke.ToSKColor();

			canvas.DrawText(Text, xText, yText, textPaint);
		}
	}
}