using System.Text;

namespace Meezi.API.Services.Printing;

public class EscPosBuilder
{
    private readonly List<byte> _buffer = [];

    public EscPosBuilder Initialize()
    {
        _buffer.AddRange([0x1B, 0x40]);
        return this;
    }

    public EscPosBuilder SetEncoding()
    {
        _buffer.AddRange([0x1B, 0x74, 0x25]);
        return this;
    }

    public EscPosBuilder AlignCenter()
    {
        _buffer.AddRange([0x1B, 0x61, 0x01]);
        return this;
    }

    public EscPosBuilder AlignRight()
    {
        _buffer.AddRange([0x1B, 0x61, 0x02]);
        return this;
    }

    public EscPosBuilder AlignLeft()
    {
        _buffer.AddRange([0x1B, 0x61, 0x00]);
        return this;
    }

    public EscPosBuilder Bold(bool on)
    {
        _buffer.AddRange([0x1B, 0x45, on ? (byte)1 : (byte)0]);
        return this;
    }

    public EscPosBuilder DoubleHeight(bool on)
    {
        _buffer.AddRange([0x1B, 0x21, on ? (byte)0x10 : (byte)0x00]);
        return this;
    }

    public EscPosBuilder Text(string text)
    {
        _buffer.AddRange(Encoding.UTF8.GetBytes(text));
        return this;
    }

    public EscPosBuilder Line(string text = "")
    {
        return Text(text + "\n");
    }

    public EscPosBuilder Separator(int width = 48, char ch = '-')
    {
        return Line(new string(ch, Math.Min(width, 64)));
    }

    public EscPosBuilder TwoColumns(string left, string right, int totalWidth = 48)
    {
        var safeLeft = left.Length > totalWidth ? left[..totalWidth] : left;
        var safeRight = right.Length > totalWidth ? right[^totalWidth..] : right;
        var pad = Math.Max(1, totalWidth - safeLeft.Length - safeRight.Length);
        var line = safeLeft + new string(' ', pad) + safeRight;
        if (line.Length > totalWidth)
            line = line[..totalWidth];
        return Line(line);
    }

    public EscPosBuilder Feed(int lines = 3)
    {
        for (var i = 0; i < lines; i++)
            _buffer.Add(0x0A);
        return this;
    }

    public EscPosBuilder Cut()
    {
        _buffer.AddRange([0x1D, 0x56, 0x42, 0x03]);
        return this;
    }

    public byte[] Build() => [.. _buffer];
}
