using XYZ.PrintService.Native;
using XYZ.PrintService.Models;

namespace XYZ.PrintService.Services;

public static class PrintExecutionService
{
    /// <summary>
    /// Validates ZPL syntax (basic validation)
    /// </summary>
    private static void ValidateZPL(string zpl)
    {
        if (string.IsNullOrWhiteSpace(zpl))
        {
            throw new ArgumentException("ZPL data cannot be empty.");
        }

        // Check for basic ZPL structure
        if (!zpl.Contains("^XA"))
        {
            throw new ArgumentException("Invalid ZPL: Missing ^XA (start label) command.");
        }

        if (!zpl.Contains("^XZ"))
        {
            throw new ArgumentException("Invalid ZPL: Missing ^XZ (end label) command.");
        }

        // Check that ^XA comes before ^XZ
        int xaIndex = zpl.IndexOf("^XA");
        int xzIndex = zpl.IndexOf("^XZ");
        if (xaIndex >= xzIndex)
        {
            throw new ArgumentException("Invalid ZPL: ^XA must come before ^XZ.");
        }
    }

    /// <summary>
    /// Prints ZPL to the specified printer with full error handling
    /// Returns print result with status information
    /// </summary>
    public static PrintResult Print(PrintRequest request)
    {
        // Validate request
        if (request == null)
        {
            throw new ArgumentNullException(nameof(request), "Print request cannot be null.");
        }

        if (string.IsNullOrWhiteSpace(request.PrinterName))
        {
            throw new ArgumentException("Printer name is required.", nameof(request.PrinterName));
        }

        if (string.IsNullOrWhiteSpace(request.Zpl))
        {
            throw new ArgumentException("ZPL data is required.", nameof(request.Zpl));
        }

        // Validate ZPL syntax
        try
        {
            ValidateZPL(request.Zpl);
        }
        catch (ArgumentException ex)
        {
            throw new Exception($"ZPL validation failed: {ex.Message}", ex);
        }

        // Detect printer language (for future EPL support)
        var language = PrinterLanguageDetector.Detect(request.PrinterName);
        var payload = request.Zpl; // future EPL transform hook

        // Send to printer with error handling
        PrintResult result;
        try
        {
            result = RawPrinterHelper.SendStringToPrinter(request.PrinterName, payload);
            result.PrinterName = request.PrinterName;
            result.Message = $"Print job submitted successfully to printer '{request.PrinterName}'";
        }
        catch (Exception ex)
        {
            throw new Exception($"Failed to print to printer '{request.PrinterName}': {ex.Message}", ex);
        }

        return result;
    }
}
