using System;
using SkiaSharp;

namespace TheGameExtreme.view
{
    public class MatrixDisplay
    {
        public SKPaint MatrixPaint { set; get; } = new SKPaint
        {
            Color = SKColors.Black,
            TextSize = 48,
            StrokeWidth = 2
        };

        public string PerspectiveFormat { set; get; } = "F0";

        public SKSize Measure(SKMatrix matrix)
        {
            return MeasureAndPaint(null, matrix, new SKPoint(), false);
        }

        public void Paint(SKCanvas canvas, SKMatrix matrix, SKPoint location)
        {
            MeasureAndPaint(canvas, matrix, location, true);
        }

        SKSize MeasureAndPaint(SKCanvas canvas, SKMatrix matrix, SKPoint location, bool doPaint)
        {
            float[] values = matrix.Values;
            string[] texts = new string[9];
            SKRect[] bounds = new SKRect[9];
            float[] widths = new float[3];

            for (int i = 0; i < 9; i++)
            {
                int row = i % 3;
                int col = i / 3;

                // Format string differently based on row
                texts[i] = values[i].ToString(row == 2 ? "F0" : (col == 2 ? PerspectiveFormat : "F2"));

                // Measure string with a '-' even if one is not present
                bool isNegative = texts[i][0] == '-';
                string text = (isNegative ? "" : "-") + texts[i];
                MatrixPaint.MeasureText(text, ref bounds[i]);

                // Get maximum width for each column
                widths[col] = Math.Max(widths[col], bounds[i].Width);

                // Measure the text again without the '-' in front
                MatrixPaint.MeasureText(texts[i], ref bounds[i]);
            }

            // Some formatting constants 
            float horzGap = MatrixPaint.TextSize;
            float horzMarg = MatrixPaint.TextSize;
            float vertMarg = MatrixPaint.FontSpacing / 4;

            // Calculate the total width and height of the matrix display
            float totalWidth = widths[0] + widths[1] + widths[2] + 2 * horzGap + 2 * horzMarg;
            float totalHeight = 3 * MatrixPaint.FontSpacing + 2 * vertMarg;

            if (doPaint)
            {
                SKPaintStyle saveStyle = MatrixPaint.Style;

                for (int i = 0; i < 9; i++)
                {
                    int row = i % 3;
                    int col = i / 3;

                    // Find x, y of upper-left corner of text
                    float x = location.X + horzMarg;

                    for (int c = 0; c < col; c++)
                    {
                        x += widths[c] + horzGap;
                    }

                    float y = location.Y + vertMarg + row * MatrixPaint.FontSpacing;

                    // Adjust for right-justified text
                    x += widths[col] - bounds[i].Width;
                    y += (MatrixPaint.FontSpacing - bounds[i].Height) / 2 - bounds[i].Top;

                    // Draw the text
                    MatrixPaint.Style = SKPaintStyle.Fill;
                    canvas.DrawText(texts[i], x, y, MatrixPaint);
                }

                // Display vertical lines at the sides of the matrix
                MatrixPaint.Style = SKPaintStyle.Stroke;
                canvas.DrawLine(location.X + horzMarg / 2, location.Y + vertMarg,
                                location.X + horzMarg / 2, location.Y + totalHeight - vertMarg, MatrixPaint);
                canvas.DrawLine(location.X + totalWidth - horzMarg / 2, location.Y + vertMarg,
                                location.X + totalWidth - horzMarg / 2, location.Y + totalHeight - vertMarg, MatrixPaint);

                MatrixPaint.Style = saveStyle;
            }
            return new SKSize(totalWidth, totalHeight);
        }
    }
}
