using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace Inspectron.Epson;

/// <summary>
/// IEpsonPrinter proxy that defers HtmlPrinter creation until ConnectAsync is called,
/// selecting the correct configuration (output file, printer ID, paper width) based on the IP address.
/// </summary>
public class EmulationPrinterProxy : IEpsonPrinter
{
    private readonly Dictionary<string, (string OutputPath, byte PrinterId, int PaperWidth)> _printerConfigs;
    private readonly ILogger? _logger;
    private HtmlPrinter? _inner;

    public EmulationPrinterProxy(
        Dictionary<string, (string OutputPath, byte PrinterId, int PaperWidth)> printerConfigs,
        ILogger? logger = null)
    {
        _printerConfigs = printerConfigs;
        _logger = logger;
    }

    public bool IsConnected => _inner?.IsConnected ?? false;

    public Task ConnectAsync(string ip, int port = 9100, int timeoutSeconds = 10)
    {
        if (!_printerConfigs.TryGetValue(ip, out var config))
            throw new EpsonConnectionException($"No emulation configuration for IP {ip}");

        _logger?.LogInformation("EmulationPrinterProxy: Creating HtmlPrinter for {IP} (id=0x{Id:X2}, width={Width}px, output={Path})",
            ip, config.PrinterId, config.PaperWidth, config.OutputPath);

        _inner = new HtmlPrinter(config.OutputPath, config.PaperWidth, _logger, config.PrinterId);
        return _inner.ConnectAsync(ip, port, timeoutSeconds);
    }

    private HtmlPrinter Inner => _inner ?? throw new EpsonConnectionException("Not connected. Call ConnectAsync first.");

    public void Disconnect() => Inner.Disconnect();
    public Task<PrinterStatus> GetPrinterStatusAsync() => Inner.GetPrinterStatusAsync();
    public Task<OfflineStatus> GetOfflineStatusAsync() => Inner.GetOfflineStatusAsync();
    public Task<ErrorStatus> GetErrorStatusAsync() => Inner.GetErrorStatusAsync();
    public Task<PaperSensorStatus> GetPaperSensorStatusAsync() => Inner.GetPaperSensorStatusAsync();
    public Task<byte> GetTM220StatusAsync() => Inner.GetTM220StatusAsync();
    public Task<byte?> GetPrinterIdAsync() => Inner.GetPrinterIdAsync();
    public Task<OverallStatus> GetOverallStatusAsync() => Inner.GetOverallStatusAsync();
    public Task InitAsync() => Inner.InitAsync();
    public Task SetQuadrupleMode(bool enable) => Inner.SetQuadrupleMode(enable);
    public Task SetRedColor(bool enable) => Inner.SetRedColor(enable);
    public Task SetEmphasized(bool enable) => Inner.SetEmphasized(enable);
    public Task SelectFont(EpsonCommands.PrinterFont font) => Inner.SelectFont(font);
    public Task SetBiggerFontTM220(bool biggerWidth, bool biggerHeight = false, bool secondaryFont = true) => Inner.SetBiggerFontTM220(biggerWidth, biggerHeight, secondaryFont);
    public Task PrintTextAsync(string text) => Inner.PrintTextAsync(text);
    public Task SetFontSizeAsync(int width, int height) => Inner.SetFontSizeAsync(width, height);
    public Task PrintTextAndCutAsync(string text, int feedLines = 5) => Inner.PrintTextAndCutAsync(text, feedLines);
    public Task PrintBuffer() => Inner.PrintBuffer();
    public Task FeedLinesAsync(int lines) => Inner.FeedLinesAsync(lines);
    public Task CutAsync(bool fullCut = true) => Inner.CutAsync(fullCut);
    public Task LoadImageAsync(string imagePath, int maxWidth = 384) => Inner.LoadImageAsync(imagePath, maxWidth);
    public Task LoadImageAsync(Stream imageStream, int maxWidth = 384) => Inner.LoadImageAsync(imageStream, maxWidth);
    public Task LoadImageAsync(Image<Rgba32> image, int maxWidth = 384) => Inner.LoadImageAsync(image, maxWidth);
    public Task PrintLoadedImage() => Inner.PrintLoadedImage();
    public Task PrintImageBitModeAsync(string imagePath, EpsonCommands.BitImageMode mode = EpsonCommands.BitImageMode.SingleDensity8Dot, int maxWidth = 10) => Inner.PrintImageBitModeAsync(imagePath, mode, maxWidth);
    public Task PrintImageBitModeAsync(Stream imageStream, EpsonCommands.BitImageMode mode = EpsonCommands.BitImageMode.DoubleDensity24Dot, int maxWidth = 384) => Inner.PrintImageBitModeAsync(imageStream, mode, maxWidth);
    public Task PrintImageBitModeAsync(Image<Rgba32> image, EpsonCommands.BitImageMode mode, int maxWidth) => Inner.PrintImageBitModeAsync(image, mode, maxWidth);
    public Task SendRawCommandAsync(byte[] command) => Inner.SendRawCommandAsync(command);
    public Task SetAbsolutePrintPosition(int x) => Inner.SetAbsolutePrintPosition(x);
    public Task SetDefaultLineSpacing() => Inner.SetDefaultLineSpacing();
    public Task SetCustomLineSpacing(int spacing = 24) => Inner.SetCustomLineSpacing(spacing);

    public ValueTask DisposeAsync()
    {
        if (_inner != null)
            return _inner.DisposeAsync();
        return ValueTask.CompletedTask;
    }
}
