using System.Text;
using SkiaSharp;
using Zebra.Sdk.Card.Containers;
using Zebra.Sdk.Card.Enumerations;
using Zebra.Sdk.Card.Graphics;
using Zebra.Sdk.Card.Printer;
using Zebra.Sdk.Comm;
using Zebra.Sdk.Printer.Discovery;

namespace FrymasterBadgeApp.Services;

public class PrinterService
{
    public async Task<bool> PrintBadge(
        Dictionary<string, object> emp,
        Dictionary<string, object> comp,
        string ip
    )
    {
        try
        {
            using var frontBitmap = GenerateFrontSide(emp, comp);
            using var backBitmap = GenerateBackSide(emp, comp);

            string frontBase64 = ConvertBitmapToBase64(frontBitmap);
            string backBase64 = ConvertBitmapToBase64(backBitmap);

            var (ok, error) = await PrintBadgeImages(frontBase64, backBase64, ip);
            return ok;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"Print Engine Error: {ex.Message}");
            return false;
        }
    }

    private SKBitmap GenerateFrontSide(
        Dictionary<string, object> emp,
        Dictionary<string, object> comp
    )
    {
        var bitmap = new SKBitmap(648, 1016);
        using var canvas = new SKCanvas(bitmap);
        canvas.Clear(SKColors.White);

        using var paint = new SKPaint { IsAntialias = true };
        using var font = new SKFont(SKTypeface.FromFamilyName("Arial"), 40);

        // 1. Draw Logo
        string logoPath = comp.InternalSafeGet("logo");
        if (File.Exists(logoPath))
        {
            using var logo = SKBitmap.Decode(logoPath);
            canvas.DrawBitmap(logo, SKRect.Create(224, 40, 200, 80));
        }

        // 2. Draw Photo
        string photoPath = emp.InternalSafeGet("ImagePath");
        if (File.Exists(photoPath))
        {
            using var photo = SKBitmap.Decode(photoPath);
            canvas.DrawBitmap(photo, SKRect.Create(149, 160, 350, 350));
        }

        // 3. Draw First Name (Red)
        paint.Color = SKColors.Red;
        font.Size = 70;
        font.Embolden = true;
        string firstName = emp.InternalSafeGet("Data2").Split(' ')[0].ToUpper();
        canvas.DrawText(firstName, 324, 600, SKTextAlign.Center, font, paint);

        // 4. Draw Full Name
        paint.Color = SKColors.Black;
        font.Size = 40;
        font.Embolden = false;
        canvas.DrawText(emp.InternalSafeGet("Data2"), 324, 660, SKTextAlign.Center, font, paint);

        // 5. Draw Barcode Text
        font.Size = 80;
        canvas.DrawText(
            $"*{emp.InternalSafeGet("Data9")}*",
            324,
            850,
            SKTextAlign.Center,
            font,
            paint
        );

        return bitmap;
    }

    private SKBitmap GenerateBackSide(
        Dictionary<string, object> emp,
        Dictionary<string, object> comp
    )
    {
        var bitmap = new SKBitmap(1016, 648);
        using var canvas = new SKCanvas(bitmap);
        canvas.Clear(SKColors.White);

        using var paint = new SKPaint { IsAntialias = true, Color = SKColors.Black };
        using var font = new SKFont(SKTypeface.FromFamilyName("Arial"), 25);

        canvas.DrawText(
            $"This badge is the property of {comp.InternalSafeGet("Name")} L.L.C.",
            508,
            100,
            SKTextAlign.Center,
            font,
            paint
        );

        canvas.DrawText(emp.InternalSafeGet("Data1"), 100, 200, SKTextAlign.Left, font, paint);
        canvas.DrawText(emp.InternalSafeGet("Data10"), 100, 240, SKTextAlign.Left, font, paint);

        canvas.DrawText(comp.InternalSafeGet("Address"), 500, 200, SKTextAlign.Left, font, paint);
        canvas.DrawText(
            $"{comp.InternalSafeGet("City")}, {comp.InternalSafeGet("State")} {comp.InternalSafeGet("Zip")}",
            500,
            240,
            SKTextAlign.Left,
            font,
            paint
        );

        font.Size = 80;
        canvas.DrawText(
            $"*{emp.InternalSafeGet("Data9")}*",
            508,
            500,
            SKTextAlign.Center,
            font,
            paint
        );

        return bitmap;
    }

    private string ConvertBitmapToBase64(SKBitmap bitmap)
    {
        using var image = SKImage.FromBitmap(bitmap);
        using var data = image.Encode(SKEncodedImageFormat.Png, 100);
        return Convert.ToBase64String(data.ToArray());
    }

    public async Task<List<string>> DiscoverPrinters()
    {
        return await Task.Run(() =>
        {
            List<string> list = new();
            var handler = new InternalStatusDiscoveryHandler();
            NetworkDiscoverer.FindPrinters(handler);
            int wait = 0;
            while (!handler.IsDiscoveryComplete && wait < 5000)
            {
                Thread.Sleep(200);
                wait += 200;
            }
            foreach (var p in handler.DiscoveredPrinters)
                list.Add(p.Address);
            return list;
        });
    }

    public async Task<(bool ok, string error)> PrintBadgeImages(
        string front,
        string back,
        string ip
    )
    {
        if (string.IsNullOrEmpty(ip))
            return (false, "No IP");
        Connection connection = new TcpConnection(ip, TcpConnection.DEFAULT_ZPL_TCP_PORT);
        Zebra.Sdk.Card.Printer.ZebraCardPrinter? cardPrinter = null;
        try
        {
            connection.Open();
            cardPrinter = ZebraCardPrinterFactory.GetInstance(connection);
            using ZebraCardGraphics g = new ZebraCardGraphics(cardPrinter);
            List<Zebra.Sdk.Card.Containers.GraphicsInfo> info = new();
            if (!string.IsNullOrEmpty(front))
            {
                g.DrawImage(
                    Convert.FromBase64String(front),
                    0,
                    0,
                    0,
                    0,
                    (Zebra.Sdk.Card.Graphics.Enumerations.RotationType)0
                );
                info.Add(
                    new Zebra.Sdk.Card.Containers.GraphicsInfo
                    {
                        Side = Zebra.Sdk.Card.Enumerations.CardSide.Front,
                        PrintType = Zebra.Sdk.Card.Enumerations.PrintType.Color,
                        GraphicData = g.CreateImage(),
                    }
                );
            }
            cardPrinter.Print(1, info);
            return (true, "");
        }
        catch (Exception ex)
        {
            return (false, ex.Message);
        }
        finally
        {
            cardPrinter?.Destroy();
            if (connection.Connected)
                connection.Close();
        }
    }
}

// Fixed missing classes and helpers
public class InternalStatusDiscoveryHandler : DiscoveryHandler
{
    public List<DiscoveredPrinter> DiscoveredPrinters { get; } = new();
    public bool IsDiscoveryComplete { get; private set; } = false;

    public void FoundPrinter(DiscoveredPrinter printer) => DiscoveredPrinters.Add(printer);

    public void DiscoveryFinished() => IsDiscoveryComplete = true;

    public void DiscoveryError(string message) => IsDiscoveryComplete = true;
}

internal static class PrinterExtensions
{
    public static string InternalSafeGet(this Dictionary<string, object> dict, string key) =>
        dict.TryGetValue(key, out var val) && val != null ? val.ToString()! : "";
}
