using System.Text;

namespace EpsonReceiptPrinter;

public sealed class EscPosBuilder
{
    private readonly List<byte> _buffer = new();
    private readonly Encoding _encoding;
    private PrinterCodePage _codePage;

    public EscPosBuilder(PrinterCodePage codePage = PrinterCodePage.PC865_Nordic, Encoding? encoding = null)
    {
        _codePage = codePage;
        _encoding = encoding ?? EncodingHelper.GetEncodingForCodePage(codePage);
    }

    public EscPosBuilder Initialize()
    {
        _buffer.AddRange(EscPosCommands.Initialize);
        _buffer.AddRange(EscPosCommands.SelectCodePage(_codePage));
        return this;
    }

    public EscPosBuilder SelectCodePage(PrinterCodePage codePage)
    {
        _codePage = codePage;
        _buffer.AddRange(EscPosCommands.SelectCodePage(codePage));
        return this;
    }

    public EscPosBuilder AlignLeft()
    {
        _buffer.AddRange(EscPosCommands.AlignLeft);
        return this;
    }

    public EscPosBuilder AlignCenter()
    {
        _buffer.AddRange(EscPosCommands.AlignCenter);
        return this;
    }

    public EscPosBuilder AlignRight()
    {
        _buffer.AddRange(EscPosCommands.AlignRight);
        return this;
    }

    public EscPosBuilder BoldOn()
    {
        _buffer.AddRange(EscPosCommands.BoldOn);
        return this;
    }

    public EscPosBuilder BoldOff()
    {
        _buffer.AddRange(EscPosCommands.BoldOff);
        return this;
    }

    public EscPosBuilder UnderlineOn()
    {
        _buffer.AddRange(EscPosCommands.UnderlineOn);
        return this;
    }

    public EscPosBuilder UnderlineOff()
    {
        _buffer.AddRange(EscPosCommands.UnderlineOff);
        return this;
    }

    public EscPosBuilder SetTextSize(TextSize size)
    {
        _buffer.AddRange(EscPosCommands.TextSize(size));
        return this;
    }

    public EscPosBuilder SetTextSize(int widthMultiplier, int heightMultiplier)
    {
        _buffer.AddRange(EscPosCommands.TextSize(widthMultiplier, heightMultiplier));
        return this;
    }

    public EscPosBuilder Write(string text)
    {
        if (!string.IsNullOrEmpty(text))
        {
            _buffer.AddRange(_encoding.GetBytes(text));
        }

        return this;
    }

    public EscPosBuilder WriteLine(string? text = null)
    {
        if (!string.IsNullOrEmpty(text))
        {
            _buffer.AddRange(_encoding.GetBytes(text));
        }

        _buffer.Add(0x0A);
        return this;
    }

    public EscPosBuilder Feed(int lines = 1)
    {
        _buffer.AddRange(EscPosCommands.Feed(lines));
        return this;
    }

    public EscPosBuilder Cut(bool partial = false)
    {
        _buffer.AddRange(partial ? EscPosCommands.CutPartial() : EscPosCommands.CutFull());
        return this;
    }

    public EscPosBuilder OpenCashDrawer()
    {
        _buffer.AddRange(EscPosCommands.OpenCashDrawer());
        return this;
    }

    public EscPosBuilder Separator(int width = 42, char character = '-')
    {
        return WriteLine(new string(character, width));
    }

    public EscPosBuilder WriteColumns(string left, string? right, int totalWidth = 42)
    {
        left ??= string.Empty;
        right ??= string.Empty;

        if (left.Length + right.Length >= totalWidth)
        {
            WriteLine(left);
            WriteLine(right.PadLeft(totalWidth));
            return this;
        }

        var spaces = totalWidth - left.Length - right.Length;
        WriteLine(left + new string(' ', spaces) + right);
        return this;
    }

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