namespace Inspectron.Epson;

/// <summary>
/// General printer status (DLE EOT 1)
/// Format: 0xx1xx10b
/// </summary>
public record PrinterStatus
{
    /// <summary>
    /// Raw status byte received from printer
    /// </summary>
    public byte RawByte { get; init; }

    /// <summary>
    /// Binary representation of status byte
    /// </summary>
    public string Binary => Convert.ToString(RawByte, 2).PadLeft(8, '0');

    /// <summary>
    /// Hex representation of status byte
    /// </summary>
    public string Hex => $"0x{RawByte:X2}";

    /// <summary>
    /// Drawer kick-out connector pin 3 is HIGH (Bit 2)
    /// </summary>
    public bool DrawerOpen { get; init; }

    /// <summary>
    /// Printer is online (Bit 3: 0=online, 1=offline)
    /// </summary>
    public bool IsOnline { get; init; }

    /// <summary>
    /// Cover is closed (Bit 5: 0=closed, 1=open)
    /// </summary>
    public bool IsCoverClosed { get; init; }

    /// <summary>
    /// Paper feed button is being pressed (Bit 6)
    /// </summary>
    public bool PaperFeedButtonPressed { get; init; }

    /// <summary>
    /// Parse printer status byte
    /// </summary>
    public static PrinterStatus Parse(byte statusByte)
    {
        return new PrinterStatus
        {
            RawByte = statusByte,
            DrawerOpen = (statusByte & 0x04) != 0,
            IsOnline = (statusByte & 0x08) == 0,
            IsCoverClosed = (statusByte & 0x20) == 0,
            PaperFeedButtonPressed = (statusByte & 0x40) != 0
        };
    }
}

/// <summary>
/// Offline status (DLE EOT 2) - Reasons for offline
/// Format: 0xx1xx10b
/// </summary>
public record OfflineStatus
{
    /// <summary>
    /// Raw status byte received from printer
    /// </summary>
    public byte RawByte { get; init; }

    /// <summary>
    /// Binary representation of status byte
    /// </summary>
    public string Binary => Convert.ToString(RawByte, 2).PadLeft(8, '0');

    /// <summary>
    /// Hex representation of status byte
    /// </summary>
    public string Hex => $"0x{RawByte:X2}";

    /// <summary>
    /// Cover is open (Bit 2)
    /// </summary>
    public bool CoverOpen { get; init; }

    /// <summary>
    /// Paper feed button is being pressed (Bit 3)
    /// </summary>
    public bool PaperFeedButton { get; init; }

    /// <summary>
    /// Paper end detected (Bit 5)
    /// </summary>
    public bool PaperEnd { get; init; }

    /// <summary>
    /// Error occurred (Bit 6)
    /// </summary>
    public bool ErrorOccurred { get; init; }

    /// <summary>
    /// Parse offline status byte
    /// </summary>
    public static OfflineStatus Parse(byte statusByte)
    {
        return new OfflineStatus
        {
            RawByte = statusByte,
            CoverOpen = (statusByte & 0x04) != 0,
            PaperFeedButton = (statusByte & 0x08) != 0,
            PaperEnd = (statusByte & 0x20) != 0,
            ErrorOccurred = (statusByte & 0x40) != 0
        };
    }
}

/// <summary>
/// Error status (DLE EOT 3)
/// Format: 0xx1xx10b
/// </summary>
public record ErrorStatus
{
    /// <summary>
    /// Raw status byte received from printer
    /// </summary>
    public byte RawByte { get; init; }

    /// <summary>
    /// Binary representation of status byte
    /// </summary>
    public string Binary => Convert.ToString(RawByte, 2).PadLeft(8, '0');

    /// <summary>
    /// Hex representation of status byte
    /// </summary>
    public string Hex => $"0x{RawByte:X2}";

    /// <summary>
    /// Recoverable error occurred (Bit 2)
    /// </summary>
    public bool RecoverableError { get; init; }

    /// <summary>
    /// Auto-cutter error occurred (Bit 3)
    /// </summary>
    public bool AutoCutterError { get; init; }

    /// <summary>
    /// Unrecoverable error occurred (Bit 5)
    /// </summary>
    public bool UnrecoverableError { get; init; }

    /// <summary>
    /// Auto-recovery error occurred (Bit 6)
    /// </summary>
    public bool AutoRecoveryError { get; init; }

    /// <summary>
    /// Returns true if any error is present
    /// </summary>
    public bool HasError => RecoverableError || AutoCutterError || UnrecoverableError || AutoRecoveryError;

    /// <summary>
    /// Parse error status byte
    /// </summary>
    public static ErrorStatus Parse(byte statusByte)
    {
        return new ErrorStatus
        {
            RawByte = statusByte,
            RecoverableError = (statusByte & 0x04) != 0,
            AutoCutterError = (statusByte & 0x08) != 0,
            UnrecoverableError = (statusByte & 0x20) != 0,
            AutoRecoveryError = (statusByte & 0x40) != 0
        };
    }
}

/// <summary>
/// Paper sensor status (DLE EOT 4)
/// Format: 0xx1xx10b
/// </summary>
public record PaperSensorStatus
{
    /// <summary>
    /// Raw status byte received from printer
    /// </summary>
    public byte RawByte { get; init; }

    /// <summary>
    /// Binary representation of status byte
    /// </summary>
    public string Binary => Convert.ToString(RawByte, 2).PadLeft(8, '0');

    /// <summary>
    /// Hex representation of status byte
    /// </summary>
    public string Hex => $"0x{RawByte:X2}";

    /// <summary>
    /// Paper roll is near end (Bits 2-3)
    /// </summary>
    public bool PaperNearEnd { get; init; }

    /// <summary>
    /// Paper is present (Bits 5-6, inverted logic)
    /// </summary>
    public bool PaperPresent { get; init; }

    /// <summary>
    /// Parse paper sensor status byte
    /// </summary>
    public static PaperSensorStatus Parse(byte statusByte)
    {
        return new PaperSensorStatus
        {
            RawByte = statusByte,
            PaperNearEnd = (statusByte & 0x0C) != 0,
            PaperPresent = (statusByte & 0x60) == 0
        };
    }
}

/// <summary>
/// Overall printer status with aggregated information and health status
/// </summary>
public record OverallStatus
{
    /// <summary>
    /// Printer model/ID
    /// </summary>
    public string? PrinterModel { get; init; }

    /// <summary>
    /// General printer status
    /// </summary>
    public PrinterStatus? PrinterStatus { get; init; }

    /// <summary>
    /// Offline status
    /// </summary>
    public OfflineStatus? OfflineStatus { get; init; }

    /// <summary>
    /// Error status
    /// </summary>
    public ErrorStatus? ErrorStatus { get; init; }

    /// <summary>
    /// Paper sensor status
    /// </summary>
    public PaperSensorStatus? PaperStatus { get; init; }

    /// <summary>
    /// Overall status text description
    /// </summary>
    public string StatusText { get; init; } = string.Empty;

    /// <summary>
    /// True if printer is ready for operation
    /// </summary>
    public bool IsReady { get; init; }

    /// <summary>
    /// List of recommendations to resolve issues
    /// </summary>
    public List<string> Recommendations { get; init; } = new();

    /// <summary>
    /// Status emoji/icon
    /// </summary>
    public string StatusIcon { get; init; } = "❓";
}
