<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Bluetooth Receipt Printer</title>
  <style>
    :root {
      --primary-color: #007bff;
      --success-color: #28a745;
      --danger-color: #dc3545;
      --warning-color: #ffc107;
      --background-color: #f9f9f9;
      --card-background: white;
      --text-color: #333;
      --border-color: #ddd;
      --shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: Arial, sans-serif;
      background-color: var(--background-color);
      padding: 20px;
      color: var(--text-color);
    }

    .container {
      max-width: 800px;
      margin: 0 auto;
      background-color: var(--card-background);
      border-radius: 8px;
      box-shadow: var(--shadow);
      padding: 30px;
    }

    h1 {
      text-align: center;
      color: var(--primary-color);
      margin-bottom: 30px;
      font-size: 2rem;
    }

    .section {
      margin-bottom: 30px;
      padding: 20px;
      background-color: #f8f9fa;
      border-radius: 8px;
      border: 1px solid var(--border-color);
    }

    .section-title {
      font-size: 1.2rem;
      font-weight: bold;
      margin-bottom: 15px;
      color: var(--text-color);
    }

    .status-indicator {
      display: inline-block;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      margin-right: 8px;
      background-color: var(--danger-color);
    }

    .status-indicator.connected {
      background-color: var(--success-color);
    }

    .status-indicator.scanning {
      background-color: var(--warning-color);
      animation: pulse 1.5s infinite;
    }

    @keyframes pulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.5; }
    }

    .status-text {
      font-weight: 500;
      margin-bottom: 15px;
    }

    .button-group {
      display: flex;
      gap: 10px;
      margin-bottom: 15px;
      flex-wrap: wrap;
    }

    button {
      padding: 12px 24px;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      font-size: 1rem;
      font-weight: 500;
      transition: all 0.3s;
      min-width: 120px;
    }

    button:hover:not(:disabled) {
      transform: translateY(-2px);
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    }

    button:active:not(:disabled) {
      transform: translateY(0);
    }

    button:disabled {
      opacity: 0.6;
      cursor: not-allowed;
    }

    .btn-primary {
      background-color: var(--primary-color);
      color: white;
    }

    .btn-primary:hover:not(:disabled) {
      background-color: #0056b3;
    }

    .btn-success {
      background-color: var(--success-color);
      color: white;
    }

    .btn-success:hover:not(:disabled) {
      background-color: #218838;
    }

    .btn-danger {
      background-color: var(--danger-color);
      color: white;
    }

    .btn-danger:hover:not(:disabled) {
      background-color: #c82333;
    }

    .btn-warning {
      background-color: var(--warning-color);
      color: #333;
    }

    .btn-warning:hover:not(:disabled) {
      background-color: #e0a800;
    }

    .device-list {
      list-style: none;
      margin-top: 15px;
    }

    .device-item {
      padding: 12px;
      margin-bottom: 10px;
      background-color: white;
      border: 2px solid var(--border-color);
      border-radius: 6px;
      cursor: pointer;
      transition: all 0.3s;
    }

    .device-item:hover {
      border-color: var(--primary-color);
      background-color: #f0f7ff;
    }

    .device-item.selected {
      border-color: var(--primary-color);
      background-color: #e7f3ff;
    }

    .device-name {
      font-weight: bold;
      margin-bottom: 5px;
    }

    .device-id {
      font-size: 0.85rem;
      color: #666;
    }

    .message {
      padding: 12px;
      border-radius: 6px;
      margin-bottom: 15px;
      display: none;
    }

    .message.show {
      display: block;
    }

    .message.success {
      background-color: #d4edda;
      color: #155724;
      border: 1px solid #c3e6cb;
    }

    .message.error {
      background-color: #f8d7da;
      color: #721c24;
      border: 1px solid #f5c6cb;
    }

    .message.info {
      background-color: #d1ecf1;
      color: #0c5460;
      border: 1px solid #bee5eb;
    }

    .receipt-preview {
      background-color: white;
      padding: 20px;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      font-family: 'Courier New', monospace;
      font-size: 0.9rem;
      white-space: pre-wrap;
      max-height: 400px;
      overflow-y: auto;
      margin-top: 15px;
    }

    .loading {
      display: inline-block;
      width: 16px;
      height: 16px;
      border: 3px solid rgba(255, 255, 255, 0.3);
      border-radius: 50%;
      border-top-color: white;
      animation: spin 0.8s linear infinite;
      margin-right: 8px;
      vertical-align: middle;
    }

    @keyframes spin {
      to { transform: rotate(360deg); }
    }

    .browser-warning {
      background-color: #fff3cd;
      color: #856404;
      border: 1px solid #ffeaa7;
      padding: 15px;
      border-radius: 6px;
      margin-bottom: 20px;
    }

    .browser-warning strong {
      display: block;
      margin-bottom: 5px;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>🖨️ Bluetooth Receipt Printer</h1>

    <!-- Browser Compatibility Warning -->
    <div class="browser-warning" id="browserWarning" style="display: none;">
      <strong>⚠️ Browser Compatibility Notice</strong>
      <p>Web Bluetooth API is only supported in Chrome/Edge browsers (desktop and Android). Please use a compatible browser for this feature.</p>
    </div>

    <!-- Bluetooth Type Warning -->
    <div class="browser-warning" id="bluetoothTypeWarning" style="display: block;">
      <strong>📱 Important: Bluetooth Type Compatibility</strong>
      <p><strong>Web Bluetooth API only supports BLE (Bluetooth Low Energy)</strong>, not Classic Bluetooth (SPP).</p>
      <p>If your printer uses Classic Bluetooth, it won't work with this web app. Please:</p>
      <ul style="margin: 10px 0 0 20px;">
        <li>Check if your printer supports BLE mode</li>
        <li>Try pairing the device in your OS Bluetooth settings first</li>
        <li>Ensure the printer is in pairing/discoverable mode</li>
        <li>Some printers have a BLE/Classic toggle - ensure BLE is enabled</li>
      </ul>
    </div>

    <!-- Backend Bridge Option -->
    <div class="section" id="backendBridgeSection" style="display: block;">
      <div class="section-title">Backend Bluetooth Bridge (For Classic Bluetooth Printers)</div>
      <div class="message info show">
        <strong>Alternative Solution for FLM-P0058:</strong> Since your printer uses Classic Bluetooth (SPP), you can use a backend bridge service (similar to your network printer setup). The backend can handle Classic Bluetooth connections and receive print jobs via HTTP API.
        <br><br>
        <strong>Note:</strong> The FLM-P0058 uses standard ESC/POS commands, so no special commands are required. The backend bridge will handle the Classic Bluetooth connection.
      </div>
      <div style="margin-top: 15px;">
        <label style="display: block; margin-bottom: 8px; font-weight: bold;">Backend Bridge URL:</label>
        <input type="text" id="bluetoothBridgeUrl" value="http://localhost:5000/api/bluetooth/print" 
               placeholder="http://localhost:5000/api/bluetooth/print" 
               style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: monospace;">
        <small style="color: #666; display: block; margin-top: 5px;">
          Enter the URL of your backend Bluetooth bridge endpoint
        </small>
      </div>
      <div style="margin-top: 15px;">
        <label style="display: block; margin-bottom: 8px; font-weight: bold;">Bluetooth Device Address/MAC:</label>
        <input type="text" id="bluetoothDeviceAddress" placeholder="00:11:22:33:44:55" 
               style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: monospace;">
        <small style="color: #666; display: block; margin-top: 5px;">
          Enter the MAC address of your Bluetooth printer (found in device settings)
        </small>
      </div>
      <div class="button-group" style="margin-top: 15px;">
        <button class="btn-primary" id="printViaBackendBtn">
          🖨️ Print via Backend Bridge
        </button>
        <button class="btn-warning" id="testBackendBtn">
          Test Backend Connection
        </button>
      </div>
    </div>

    <!-- Connection Status Section -->
    <div class="section">
      <div class="section-title">Connection Status</div>
      <div class="status-text">
        <span class="status-indicator" id="statusIndicator"></span>
        <span id="statusText">Not Connected</span>
      </div>
      <div class="message" id="statusMessage"></div>
    </div>

    <!-- Device Selection Section -->
    <div class="section">
      <div class="section-title">Bluetooth Device</div>
      <div style="margin-bottom: 15px;">
        <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
          <input type="checkbox" id="autoConnectCheckbox" checked>
          <span>Auto-connect after device selection</span>
        </label>
      </div>
      <div class="button-group">
        <button class="btn-primary" id="scanBtn">
          <span id="scanBtnText">🔍 Scan & Connect</span>
        </button>
        <button class="btn-success" id="quickPrintBtn">
          ⚡ Quick Print (Scan → Connect → Print)
        </button>
        <button class="btn-success" id="connectBtn" disabled>
          Connect
        </button>
        <button class="btn-danger" id="disconnectBtn" disabled>
          Disconnect
        </button>
      </div>
      <ul class="device-list" id="deviceList"></ul>
    </div>

    <!-- Print Section -->
    <div class="section">
      <div class="section-title">Print Receipt</div>
      <div style="margin-bottom: 15px;">
        <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
          <input type="checkbox" id="useBackendCheckbox" checked>
          <span><strong>Use Backend Bridge</strong> (Required for FLM-P0058 / Classic Bluetooth printers)</span>
        </label>
        <small style="color: #666; display: block; margin-left: 28px; margin-top: 5px;">
          Check this to use backend printing (works with Classic Bluetooth). Uncheck to try direct Web Bluetooth (BLE only).
        </small>
      </div>
      <div style="margin-bottom: 15px;">
        <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
          <input type="checkbox" id="autoPrintCheckbox">
          <span>Auto-print immediately after connection</span>
        </label>
      </div>
      <div class="button-group">
        <button class="btn-primary" id="printBtn">
          🖨️ Print Sample Receipt
        </button>
        <button class="btn-warning" id="previewBtn">
          👁️ Preview Receipt
        </button>
      </div>
      <div class="receipt-preview" id="receiptPreview" style="display: none;"></div>
    </div>

    <!-- Debug Section (for troubleshooting) -->
    <div class="section" id="debugSection" style="display: none;">
      <div class="section-title">Debug Information</div>
      <div id="debugInfo" style="font-family: monospace; font-size: 0.85rem; white-space: pre-wrap; max-height: 300px; overflow-y: auto; background: #f8f9fa; padding: 10px; border-radius: 4px;"></div>
      <div style="margin-top: 10px; display: flex; gap: 10px;">
        <button class="btn-warning" id="toggleDebugBtn">
          Hide Debug Info
        </button>
        <button class="btn-warning" id="clearDebugBtn">
          Clear Debug Info
        </button>
      </div>
    </div>
    <div class="section">
      <button class="btn-warning" id="showDebugBtn">
        Show Debug Info
      </button>
    </div>
  </div>

  <script>
    class BluetoothPrinter {
      constructor() {
        this.device = null;
        this.server = null;
        this.characteristic = null;
        this.selectedDevice = null;
        this.devices = [];
        
        // Check browser support
        this.checkBrowserSupport();
        
        // Initialize UI
        this.initializeUI();
      }

      checkBrowserSupport() {
        if (!navigator.bluetooth) {
          document.getElementById('browserWarning').style.display = 'block';
          this.showMessage('Web Bluetooth API is not supported in this browser. Please use Chrome or Edge.', 'error');
        }
      }

      initializeUI() {
        // Button event listeners
        document.getElementById('scanBtn').addEventListener('click', () => this.scanDevices());
        document.getElementById('quickPrintBtn').addEventListener('click', () => this.quickPrint());
        document.getElementById('connectBtn').addEventListener('click', () => this.connect());
        document.getElementById('disconnectBtn').addEventListener('click', () => this.disconnect());
        document.getElementById('printBtn').addEventListener('click', () => this.printReceipt());
        document.getElementById('previewBtn').addEventListener('click', () => this.previewReceipt());
        document.getElementById('toggleDebugBtn').addEventListener('click', () => this.toggleDebug());
        document.getElementById('showDebugBtn').addEventListener('click', () => this.showDebug());
        document.getElementById('clearDebugBtn').addEventListener('click', () => this.clearDebug());
        document.getElementById('printViaBackendBtn').addEventListener('click', () => this.printViaBackend());
        document.getElementById('testBackendBtn').addEventListener('click', () => this.testBackendConnection());
      }

      addDebugInfo(message) {
        const debugSection = document.getElementById('debugSection');
        const debugInfo = document.getElementById('debugInfo');
        if (debugSection && debugInfo) {
          debugSection.style.display = 'block';
          const timestamp = new Date().toLocaleTimeString();
          debugInfo.textContent += `[${timestamp}] ${message}\n`;
          debugInfo.scrollTop = debugInfo.scrollHeight;
        }
        console.log(message);
      }

      showDebug() {
        const debugSection = document.getElementById('debugSection');
        if (debugSection) {
          debugSection.style.display = 'block';
        }
      }

      toggleDebug() {
        const debugSection = document.getElementById('debugSection');
        const toggleBtn = document.getElementById('toggleDebugBtn');
        if (debugSection && toggleBtn) {
          if (debugSection.style.display === 'none') {
            debugSection.style.display = 'block';
            toggleBtn.textContent = 'Hide Debug Info';
          } else {
            debugSection.style.display = 'none';
            toggleBtn.textContent = 'Show Debug Info';
          }
        }
      }

      clearDebug() {
        const debugInfo = document.getElementById('debugInfo');
        if (debugInfo) {
          debugInfo.textContent = '';
        }
      }

      async scanDevices() {
        if (!navigator.bluetooth) {
          this.showMessage('Bluetooth API not available. Please use Chrome or Edge browser.', 'error');
          return;
        }

        const scanBtn = document.getElementById('scanBtn');
        const scanBtnText = document.getElementById('scanBtnText');
        const deviceList = document.getElementById('deviceList');
        
        try {
          scanBtn.disabled = true;
          scanBtnText.innerHTML = '<span class="loading"></span> Scanning...';
          this.updateStatus('scanning', 'Scanning for devices...');
          deviceList.innerHTML = '';
          this.clearDebug();
          this.addDebugInfo('Starting device scan...');

          // Comprehensive list of common Bluetooth printer service UUIDs
          const serviceUUIDs = [
            '00001101-0000-1000-8000-00805f9b34fb', // Serial Port Profile (SPP) - Most common
            '000018f0-0000-1000-8000-00805f9b34fb', // Some ESC/POS printers
            '0000ae30-0000-1000-8000-00805f9b34fb', // Some printers
            '0000fff0-0000-1000-8000-00805f9b34fb', // Common printer service
            '0000fff1-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff2-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff3-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff4-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff5-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff6-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '49535343-fe7d-4ae5-8fa9-9fafd205e455', // Nordic UART Service
            '6e400001-b5a3-f393-e0a9-e50e24dcca9e', // Nordic UART Service (alternative)
          ];

          const options = {
            acceptAllDevices: true, // Accept all devices for broader compatibility
            optionalServices: serviceUUIDs // Request all possible services
          };

          this.device = await navigator.bluetooth.requestDevice(options);
          this.addDebugInfo(`✓ Device selected: ${this.device.name || 'Unknown'} (${this.device.id})`);
          
          // Store the device
          this.selectedDevice = this.device;
          this.devices = [this.device];
          
          // Display found device
          this.displayDevices();
          
          this.showMessage('Device found!', 'success');
          this.addDebugInfo('Device ready for connection.');
          
          // Auto-connect if checkbox is checked
          const autoConnect = document.getElementById('autoConnectCheckbox').checked;
          if (autoConnect) {
            this.addDebugInfo('Auto-connect enabled. Connecting automatically...');
            this.showMessage('Auto-connecting to device...', 'info');
            // Small delay to let UI update
            setTimeout(() => {
              this.connect();
            }, 500);
          } else {
            this.showMessage('Device found! Click Connect to establish connection.', 'success');
            document.getElementById('connectBtn').disabled = false;
          }
          
        } catch (error) {
          if (error.name === 'NotFoundError') {
            this.showMessage('No Bluetooth device selected.', 'info');
          } else if (error.name === 'SecurityError') {
            this.showMessage('Bluetooth permission denied. Please allow Bluetooth access.', 'error');
          } else {
            this.showMessage(`Scan failed: ${error.message}`, 'error');
          }
          console.error('Scan error:', error);
        } finally {
          scanBtn.disabled = false;
          scanBtnText.textContent = '🔍 Scan for Devices';
          this.updateStatus('disconnected', 'Not Connected');
        }
      }

      displayDevices() {
        const deviceList = document.getElementById('deviceList');
        deviceList.innerHTML = '';

        this.devices.forEach((device, index) => {
          const li = document.createElement('li');
          li.className = 'device-item';
          if (device === this.selectedDevice) {
            li.classList.add('selected');
          }
          
          li.innerHTML = `
            <div class="device-name">${device.name || 'Unknown Device'}</div>
            <div class="device-id">ID: ${device.id}</div>
          `;
          
          li.addEventListener('click', () => {
            this.selectedDevice = device;
            this.displayDevices();
            document.getElementById('connectBtn').disabled = false;
          });
          
          deviceList.appendChild(li);
        });
      }

      async connect() {
        if (!this.selectedDevice) {
          this.showMessage('Please select a device first.', 'error');
          return;
        }

        const connectBtn = document.getElementById('connectBtn');
        const disconnectBtn = document.getElementById('disconnectBtn');
        const printBtn = document.getElementById('printBtn');

        try {
          connectBtn.disabled = true;
          this.updateStatus('scanning', 'Connecting...');
          this.showMessage('Connecting to device...', 'info');

          // Connect to GATT server
          this.addDebugInfo(`Connecting to device: ${this.selectedDevice.name || 'Unknown'}`);
          this.addDebugInfo(`Device ID: ${this.selectedDevice.id}`);
          
          try {
            // Try connecting with retry logic
            let retries = 2;
            let lastError = null;
            
            for (let i = 0; i <= retries; i++) {
              try {
                if (i > 0) {
                  this.addDebugInfo(`Retry attempt ${i}/${retries}...`);
                  this.showMessage(`Retrying connection (${i}/${retries})...`, 'info');
                  await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second between retries
                }
                
                this.server = await this.selectedDevice.gatt.connect();
                this.addDebugInfo('✓ GATT server connected successfully');
                this.showMessage('GATT server connected. Discovering services...', 'info');
                break; // Success, exit retry loop
              } catch (connectError) {
                lastError = connectError;
                this.addDebugInfo(`✗ GATT connection attempt ${i + 1} failed: ${connectError.message}`);
                this.addDebugInfo(`  Error name: ${connectError.name}`);
                
                if (i === retries) {
                  // Last attempt failed
                  let errorMsg = `Failed to connect to GATT server: ${connectError.message}`;
                  
                  // Provide specific guidance based on error type
                  if (connectError.message.includes('GATT operation failed') || connectError.message.includes('unknown reason')) {
                    errorMsg += '\n\nPossible solutions:\n';
                    errorMsg += '1. Ensure the printer is powered on and in range\n';
                    errorMsg += '2. Try disconnecting and reconnecting the device\n';
                    errorMsg += '3. Pair the device in your OS Bluetooth settings first\n';
                    errorMsg += '4. Restart the printer\n';
                    errorMsg += '5. The device may use Classic Bluetooth (not supported)';
                  } else if (connectError.name === 'NetworkError') {
                    errorMsg += '\n\nNetwork error - device may be out of range or disconnected.';
                  } else if (connectError.name === 'SecurityError') {
                    errorMsg += '\n\nSecurity error - Bluetooth permissions may be required.';
                  }
                  
                  throw new Error(errorMsg);
                }
              }
            }
          } catch (connectError) {
            this.addDebugInfo(`✗✗✗ Final GATT connection failed after retries`);
            throw connectError;
          }
          
          // Comprehensive list of common Bluetooth printer service UUIDs
          const serviceUUIDs = [
            '00001101-0000-1000-8000-00805f9b34fb', // Serial Port Profile (SPP) - Most common
            '000018f0-0000-1000-8000-00805f9b34fb', // Some ESC/POS printers
            '0000ae30-0000-1000-8000-00805f9b34fb', // Some printers
            '0000fff0-0000-1000-8000-00805f9b34fb', // Common printer service
            '0000fff1-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff2-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff3-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff4-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff5-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '0000fff6-0000-1000-8000-00805f9b34fb', // Some thermal printers
            '49535343-fe7d-4ae5-8fa9-9fafd205e455', // Nordic UART Service
            '6e400001-b5a3-f393-e0a9-e50e24dcca9e', // Nordic UART Service (alternative)
          ];

          // First, try to get all primary services (discover all available services)
          let allServices = [];
          
          // Check server connection status
          this.addDebugInfo(`Server connected: ${this.server.connected}`);
          this.addDebugInfo(`Device: ${this.selectedDevice.name || 'Unknown'}`);
          
          try {
            // Try without any parameters first
            this.addDebugInfo('Attempting to discover all services...');
            allServices = await this.server.getPrimaryServices();
            this.addDebugInfo(`✓ Found ${allServices.length} primary service(s):`);
            
            if (allServices.length === 0) {
              this.addDebugInfo('⚠⚠⚠ CRITICAL: No services found via getPrimaryServices()');
              this.addDebugInfo('This strongly indicates the device uses Classic Bluetooth (SPP)');
              this.addDebugInfo('Classic Bluetooth is NOT supported by Web Bluetooth API');
              this.addDebugInfo('');
              this.addDebugInfo('SOLUTIONS:');
              this.addDebugInfo('1. Check if printer has BLE mode (Bluetooth Low Energy)');
              this.addDebugInfo('2. Try pairing device in OS Bluetooth settings first');
              this.addDebugInfo('3. Look for BLE/Classic toggle in printer settings');
              this.addDebugInfo('4. Some printers need to be in "pairing mode" for BLE');
            } else {
              allServices.forEach((svc, idx) => {
                this.addDebugInfo(`  Service ${idx + 1}: ${svc.uuid} (${svc.isPrimary ? 'primary' : 'secondary'})`);
              });
            }
          } catch (e) {
            this.addDebugInfo(`⚠ Error getting all primary services: ${e.message}`);
            this.addDebugInfo(`  Error name: ${e.name}`);
            this.addDebugInfo(`  Error stack: ${e.stack}`);
            console.warn('Could not get all primary services:', e);
            
            // Try alternative: request services individually
            this.addDebugInfo('');
            this.addDebugInfo('Trying alternative service discovery method...');
            this.addDebugInfo('Attempting to request services individually...');
            
            try {
              // Some devices require services to be requested individually
              const testPromises = serviceUUIDs.map(async (uuid) => {
                try {
                  const svc = await this.server.getPrimaryService(uuid);
                  this.addDebugInfo(`  ✓ Found service: ${uuid}`);
                  return svc;
                } catch (err) {
                  // Silently fail for individual services
                  return null;
                }
              });
              
              const testResults = await Promise.all(testPromises);
              const foundServices = testResults.filter(svc => svc !== null);
              
              if (foundServices.length > 0) {
                this.addDebugInfo(`✓✓✓ Alternative method found ${foundServices.length} service(s)!`);
                allServices = foundServices;
              } else {
                this.addDebugInfo(`✗ Alternative method found 0 services`);
              }
            } catch (e2) {
              this.addDebugInfo(`✗ Alternative method also failed: ${e2.message}`);
            }
          }
          
          // Additional diagnostic: try to access device info service
          if (allServices.length === 0) {
            this.addDebugInfo('');
            this.addDebugInfo('Trying to access Device Information Service (standard BLE service)...');
            try {
              const deviceInfoService = await this.server.getPrimaryService('0000180a-0000-1000-8000-00805f9b34fb');
              this.addDebugInfo('✓ Device Information Service found - device DOES support BLE!');
              allServices.push(deviceInfoService);
            } catch (e) {
              this.addDebugInfo('✗ Device Information Service not found');
            }
          }

          // Try known service UUIDs first
          let service = null;
          let foundServiceUUID = null;
          
          for (const uuid of serviceUUIDs) {
            try {
              service = await this.server.getPrimaryService(uuid);
              foundServiceUUID = uuid;
              this.addDebugInfo(`✓ Found service with UUID: ${uuid}`);
              break;
            } catch (e) {
              // Try next UUID
              this.addDebugInfo(`✗ Service ${uuid} not found`);
              continue;
            }
          }

          // If no known service found, try all discovered services
          if (!service && allServices.length > 0) {
            this.showMessage(`Trying ${allServices.length} discovered service(s)...`, 'info');
            this.addDebugInfo(`Trying ${allServices.length} discovered service(s)...`);
            for (const svc of allServices) {
              try {
                // Try to get characteristics from this service
                const characteristics = await svc.getCharacteristics();
                this.addDebugInfo(`Service ${svc.uuid} has ${characteristics.length} characteristic(s)`);
                
                // Check if any characteristic is writable
                const writableChar = characteristics.find(c => 
                  c.properties.write || c.properties.writeWithoutResponse
                );
                
                if (writableChar) {
                  service = svc;
                  foundServiceUUID = svc.uuid;
                  this.addDebugInfo(`✓ Using service: ${svc.uuid} (found writable characteristic)`);
                  break;
                } else {
                  this.addDebugInfo(`✗ Service ${svc.uuid} has no writable characteristics`);
                }
              } catch (e) {
                this.addDebugInfo(`✗ Error checking service ${svc.uuid}: ${e.message}`);
                console.warn(`Error checking service ${svc.uuid}:`, e);
                continue;
              }
            }
          }

          if (!service) {
            // Last attempt: try to get any service without UUID
            this.addDebugInfo('Last attempt: trying to access device services directly...');
            try {
              // Some devices expose services that aren't in the standard list
              // Try to access GATT services directly
              if (this.server.connected) {
                this.addDebugInfo('Device is connected, but no services found.');
                this.addDebugInfo('Possible reasons:');
                this.addDebugInfo('  1. Device uses Classic Bluetooth (SPP) - not supported by Web Bluetooth API');
                this.addDebugInfo('  2. Device requires OS-level pairing first');
                this.addDebugInfo('  3. Device services are not discoverable');
                this.addDebugInfo('  4. Device needs to be in a specific mode');
                
                // Show backend bridge option
                document.getElementById('backendBridgeSection').style.display = 'block';
                this.addDebugInfo('');
                this.addDebugInfo('💡 SOLUTION: Use Backend Bluetooth Bridge');
                this.addDebugInfo('   Since this printer uses Classic Bluetooth, you need a backend service');
                this.addDebugInfo('   to handle the Bluetooth connection. See "Backend Bluetooth Bridge" section below.');
              }
            } catch (e) {
              this.addDebugInfo(`Error in last attempt: ${e.message}`);
            }
            
            const errorMsg = allServices.length === 0 
              ? 'No Bluetooth services found on device. The printer uses Classic Bluetooth (SPP) which is not supported by Web Bluetooth API. Please use the Backend Bluetooth Bridge option below, or ensure the printer supports BLE mode.'
              : 'No suitable Bluetooth service found with writable characteristics. Make sure the printer is powered on and in pairing mode.';
            
            throw new Error(errorMsg);
          }

          this.showMessage(`Service found (${foundServiceUUID}). Finding writable characteristic...`, 'info');

          // Comprehensive list of common characteristic UUIDs for writing
          const characteristicUUIDs = [
            '0000fff1-0000-1000-8000-00805f9b34fb', // Common write characteristic
            '0000fff2-0000-1000-8000-00805f9b34fb', // Common write characteristic
            '0000fff3-0000-1000-8000-00805f9b34fb', // Common write characteristic
            '6e400002-b5a3-f393-e0a9-e50e24dcca9e', // Nordic UART TX (write)
            '6e400003-b5a3-f393-e0a9-e50e24dcca9e', // Nordic UART RX (read)
            '49535343-8841-43f4-a8d4-ecbe34729bb3', // Nordic UART TX (write)
            '49535343-1e4d-4bd9-ba61-23c647249616', // Nordic UART RX (read)
            '00002a00-0000-1000-8000-00805f9b34fb', // Device Name (sometimes writable)
            '0000ae01-0000-1000-8000-00805f9b34fb', // Some printers
            '0000ae02-0000-1000-8000-00805f9b34fb', // Some printers
          ];

          let characteristic = null;
          let foundCharUUID = null;

          // Try known characteristic UUIDs first
          for (const uuid of characteristicUUIDs) {
            try {
              const char = await service.getCharacteristic(uuid);
              if (char.properties.write || char.properties.writeWithoutResponse) {
                characteristic = char;
                foundCharUUID = uuid;
                this.addDebugInfo(`✓ Found writable characteristic: ${uuid}`);
                break;
              } else {
                this.addDebugInfo(`✗ Characteristic ${uuid} is not writable`);
              }
            } catch (e) {
              this.addDebugInfo(`✗ Characteristic ${uuid} not found`);
              continue;
            }
          }

          // If no known characteristic found, try all characteristics in the service
          if (!characteristic) {
            this.showMessage('Trying all characteristics in service...', 'info');
            this.addDebugInfo('Trying all characteristics in service...');
            try {
              const allCharacteristics = await service.getCharacteristics();
              this.addDebugInfo(`Service has ${allCharacteristics.length} characteristic(s):`);
              
              for (const char of allCharacteristics) {
                const props = `write=${char.properties.write}, writeWithoutResponse=${char.properties.writeWithoutResponse}`;
                this.addDebugInfo(`  Characteristic ${char.uuid}: ${props}`);
                
                if (char.properties.write || char.properties.writeWithoutResponse) {
                  characteristic = char;
                  foundCharUUID = char.uuid;
                  this.addDebugInfo(`✓ Using characteristic: ${char.uuid}`);
                  break;
                }
              }
            } catch (e) {
              this.addDebugInfo(`✗ Error getting characteristics: ${e.message}`);
              console.error('Error getting characteristics:', e);
            }
          }

          if (!characteristic) {
            throw new Error('No writable characteristic found. The device may not support printing via this method.');
          }

          this.characteristic = characteristic;
          this.addDebugInfo(`✓✓✓ SUCCESS! Connected to printer`);
          this.addDebugInfo(`  Service UUID: ${foundServiceUUID}`);
          this.addDebugInfo(`  Characteristic UUID: ${foundCharUUID}`);
          console.log(`Successfully found service and characteristic. Service: ${foundServiceUUID}, Characteristic: ${foundCharUUID}`);

          // Listen for disconnection
          this.selectedDevice.addEventListener('gattserverdisconnected', () => {
            this.handleDisconnection();
          });

          this.updateStatus('connected', `Connected to ${this.selectedDevice.name || 'Device'}`);
          this.showMessage('Successfully connected to printer! Ready to print.', 'success');
          
          connectBtn.disabled = true;
          disconnectBtn.disabled = false;
          printBtn.disabled = false;
          
          // Auto-print if checkbox is checked
          const autoPrint = document.getElementById('autoPrintCheckbox').checked;
          if (autoPrint) {
            this.addDebugInfo('Auto-print enabled. Printing immediately...');
            // Small delay to ensure connection is fully established
            setTimeout(() => {
              this.printReceipt();
            }, 300);
          }

        } catch (error) {
          this.addDebugInfo(`✗✗✗ CONNECTION FAILED: ${error.message}`);
          this.addDebugInfo(`  Error name: ${error.name}`);
          this.showMessage(`Connection failed: ${error.message}`, 'error');
          this.updateStatus('disconnected', 'Connection Failed');
          console.error('Connection error:', error);
          console.error('Error details:', {
            name: error.name,
            message: error.message,
            stack: error.stack
          });
        } finally {
          connectBtn.disabled = false;
        }
      }

      handleDisconnection() {
        this.device = null;
        this.server = null;
        this.characteristic = null;
        this.updateStatus('disconnected', 'Disconnected');
        this.showMessage('Device disconnected.', 'info');
        
        document.getElementById('connectBtn').disabled = false;
        document.getElementById('disconnectBtn').disabled = true;
        document.getElementById('printBtn').disabled = true;
      }

      async disconnect() {
        try {
          if (this.server && this.server.connected) {
            this.server.disconnect();
          }
          this.handleDisconnection();
        } catch (error) {
          console.error('Disconnect error:', error);
          this.handleDisconnection();
        }
      }

      generateSampleReceipt() {
        const encoder = new TextEncoder();
        const now = new Date();
        const dateStr = now.toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
        const timeStr = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
        
        // Compact receipt to fit within 512 bytes
        const commands = [
          '\x1B\x40', // Initialize printer
          '\x1B\x61\x01', // Center align
          '\x1B\x21\x10', // Double height
          'CAFE RECEIPT\n',
          '\x1B\x21\x00', // Normal text
          '\x1B\x61\x00', // Left align
          `${'='.repeat(32)}\n`,
          `Date: ${dateStr}\n`,
          `Time: ${timeStr}\n`,
          `Receipt #: SAMPLE-001\n`,
          `${'='.repeat(32)}\n`,
          'Item            Qty  Price\n',
          `${'-'.repeat(32)}\n`,
          'Coffee           2  $10.00\n',
          'Sandwich         1   $8.00\n',
          'Juice            1   $5.00\n',
          `${'-'.repeat(32)}\n`,
          `Subtotal:       $23.00\n`,
          `Tax (10%):       $2.30\n`,
          `${'='.repeat(32)}\n`,
          '\x1B\x21\x10', // Double height
          `Total:          $25.30\n`,
          '\x1B\x21\x00', // Normal text
          `${'='.repeat(32)}\n`,
          '\x1B\x61\x01', // Center align
          'Thank you!\n',
          '\x1B\x61\x00', // Left align
          '\n\n',
          '\x1B\x69', // Cut paper (if supported)
        ];

        const receiptData = encoder.encode(commands.join(''));
        
        // Check size and warn if too large
        if (receiptData.length > 512) {
          console.warn(`Receipt size (${receiptData.length} bytes) exceeds 512 bytes limit. Truncating...`);
          // Return truncated version
          return receiptData.slice(0, 512);
        }
        
        return receiptData;
      }

      async printReceipt() {
        // Check if user wants to use backend bridge
        const useBackend = document.getElementById('useBackendCheckbox').checked;
        
        if (useBackend) {
          // Use backend bridge method
          const deviceAddress = document.getElementById('bluetoothDeviceAddress').value.trim();
          if (!deviceAddress) {
            this.showMessage('Please enter Bluetooth Device MAC Address in the Backend Bridge section above.', 'error');
            // Show backend bridge section if hidden
            document.getElementById('backendBridgeSection').style.display = 'block';
            return;
          }
          
          // Call backend print method
          await this.printViaBackend();
          return;
        }
        
        // Use direct Web Bluetooth method (for BLE printers)
        if (!this.characteristic) {
          // If not connected but device is selected, try to connect first
          if (this.selectedDevice && !this.server) {
            this.showMessage('Connecting to printer first...', 'info');
            try {
              await this.connect();
              // Wait a bit for connection to stabilize
              await new Promise(resolve => setTimeout(resolve, 500));
            } catch (error) {
              this.showMessage(`Connection failed: ${error.message}`, 'error');
              return;
            }
          } else if (!this.characteristic) {
            this.showMessage('Not connected to printer. Please connect first or use Backend Bridge option.', 'error');
            return;
          }
        }

        const printBtn = document.getElementById('printBtn');
        
        try {
          printBtn.disabled = true;
          printBtn.innerHTML = '<span class="loading"></span> Printing...';
          this.showMessage('Sending print data...', 'info');
          this.addDebugInfo('Starting print job...');

          const receiptData = this.generateSampleReceipt();
          this.addDebugInfo(`Receipt data size: ${receiptData.length} bytes`);
          
          // Convert Uint8Array to ArrayBuffer
          const buffer = receiptData.buffer.slice(
            receiptData.byteOffset,
            receiptData.byteOffset + receiptData.byteLength
          );

          // Write data to characteristic
          this.addDebugInfo('Writing data to printer...');
          if (this.characteristic.properties.writeWithoutResponse) {
            await this.characteristic.writeValueWithoutResponse(buffer);
            this.addDebugInfo('✓ Data sent using writeWithoutResponse');
          } else if (this.characteristic.properties.write) {
            await this.characteristic.writeValue(buffer);
            this.addDebugInfo('✓ Data sent using write');
          } else {
            throw new Error('Characteristic does not support writing');
          }

          this.showMessage('Receipt sent to printer successfully!', 'success');
          this.addDebugInfo('✓✓✓ Print job completed successfully!');
          
        } catch (error) {
          this.showMessage(`Print failed: ${error.message}`, 'error');
          this.addDebugInfo(`✗ Print error: ${error.message}`);
          console.error('Print error:', error);
        } finally {
          printBtn.disabled = false;
          printBtn.innerHTML = '🖨️ Print Sample Receipt';
        }
      }

      // Quick print function - scan, connect, and print in one go
      async quickPrint() {
        const quickPrintBtn = document.getElementById('quickPrintBtn');
        const originalText = quickPrintBtn.innerHTML;
        
        // Check if user wants to use backend bridge
        const useBackend = document.getElementById('useBackendCheckbox').checked;
        
        if (useBackend) {
          // Use backend bridge method for quick print
          const deviceAddress = document.getElementById('bluetoothDeviceAddress').value.trim();
          if (!deviceAddress) {
            this.showMessage('Please enter Bluetooth Device MAC Address in the Backend Bridge section above.', 'error');
            document.getElementById('backendBridgeSection').style.display = 'block';
            return;
          }
          
          // Show backend section and print
          document.getElementById('backendBridgeSection').style.display = 'block';
          await this.printViaBackend();
          return;
        }
        
        try {
          quickPrintBtn.disabled = true;
          quickPrintBtn.innerHTML = '<span class="loading"></span> Quick Printing...';
          
          this.clearDebug();
          this.addDebugInfo('=== QUICK PRINT MODE (Web Bluetooth) ===');
          this.showDebug();
          
          this.addDebugInfo('Step 1: Scanning for devices...');
          this.showMessage('Scanning for printer...', 'info');
          
          // Scan for device (this will trigger device selection dialog)
          if (!navigator.bluetooth) {
            throw new Error('Bluetooth API not available');
          }
          
          const serviceUUIDs = [
            '00001101-0000-1000-8000-00805f9b34fb',
            '000018f0-0000-1000-8000-00805f9b34fb',
            '0000fff0-0000-1000-8000-00805f9b34fb',
            '0000fff1-0000-1000-8000-00805f9b34fb',
            '49535343-fe7d-4ae5-8fa9-9fafd205e455',
            '6e400001-b5a3-f393-e0a9-e50e24dcca9e',
          ];

          const options = {
            acceptAllDevices: true,
            optionalServices: serviceUUIDs
          };

          this.device = await navigator.bluetooth.requestDevice(options);
          this.selectedDevice = this.device;
          this.devices = [this.device];
          this.addDebugInfo(`✓ Device selected: ${this.device.name || 'Unknown'}`);
          
          this.addDebugInfo('Step 2: Connecting to device...');
          this.showMessage('Connecting to printer...', 'info');
          
          // Connect
          await this.connect();
          
          // Wait for connection to stabilize
          await new Promise(resolve => setTimeout(resolve, 500));
          
          if (!this.characteristic) {
            throw new Error('Connection established but no writable characteristic found');
          }
          
          this.addDebugInfo('Step 3: Printing receipt...');
          this.showMessage('Printing receipt...', 'info');
          
          // Print directly using the characteristic
          const receiptData = this.generateSampleReceipt();
          this.addDebugInfo(`Receipt data size: ${receiptData.length} bytes`);
          
          const buffer = receiptData.buffer.slice(
            receiptData.byteOffset,
            receiptData.byteOffset + receiptData.byteLength
          );

          this.addDebugInfo('Writing data to printer...');
          
          // Try writing with retry logic
          let writeRetries = 2;
          let writeSuccess = false;
          
          for (let i = 0; i <= writeRetries; i++) {
            try {
              if (i > 0) {
                this.addDebugInfo(`Retry write attempt ${i}/${writeRetries}...`);
                this.showMessage(`Retrying print (${i}/${writeRetries})...`, 'info');
                await new Promise(resolve => setTimeout(resolve, 500));
              }
              
              if (this.characteristic.properties.writeWithoutResponse) {
                await this.characteristic.writeValueWithoutResponse(buffer);
                this.addDebugInfo('✓ Data sent using writeWithoutResponse');
                writeSuccess = true;
                break;
              } else if (this.characteristic.properties.write) {
                await this.characteristic.writeValue(buffer);
                this.addDebugInfo('✓ Data sent using write');
                writeSuccess = true;
                break;
              } else {
                throw new Error('Characteristic does not support writing');
              }
            } catch (writeError) {
              this.addDebugInfo(`✗ Write attempt ${i + 1} failed: ${writeError.message}`);
              
              if (i === writeRetries) {
                throw new Error(`Failed to write data after ${writeRetries + 1} attempts: ${writeError.message}. The device may have disconnected or the connection is unstable.`);
              }
            }
          }
          
          this.addDebugInfo('=== QUICK PRINT COMPLETE ===');
          this.showMessage('Receipt printed successfully!', 'success');
          
        } catch (error) {
          if (error.name === 'NotFoundError') {
            this.showMessage('No device selected. Quick print cancelled.', 'info');
          } else {
            // Enhanced error message with troubleshooting tips
            let errorMsg = error.message;
            
            if (error.message.includes('GATT operation failed') || error.message.includes('unknown reason')) {
              errorMsg = `GATT operation failed. This usually means:\n\n`;
              errorMsg += `• The device is not in range or disconnected\n`;
              errorMsg += `• The device needs to be paired first in OS settings\n`;
              errorMsg += `• The printer may use Classic Bluetooth (not supported by Web Bluetooth)\n`;
              errorMsg += `• Try restarting the printer and your device\n\n`;
              errorMsg += `Original error: ${error.message}`;
            }
            
            this.showMessage(`Quick print failed: ${errorMsg}`, 'error');
            this.addDebugInfo(`✗ Quick print error: ${error.message}`);
            this.addDebugInfo(`  Error name: ${error.name}`);
            this.addDebugInfo(`  Error stack: ${error.stack || 'N/A'}`);
            
            // Show backend bridge option if GATT fails
            if (error.message.includes('GATT') || error.message.includes('service')) {
              document.getElementById('backendBridgeSection').style.display = 'block';
              this.addDebugInfo('');
              this.addDebugInfo('💡 ALTERNATIVE: Use Backend Bluetooth Bridge');
              this.addDebugInfo('   Since direct Bluetooth connection failed, try the backend bridge option below.');
            }
          }
          console.error('Quick print error:', error);
          console.error('Error details:', {
            name: error.name,
            message: error.message,
            stack: error.stack
          });
        } finally {
          quickPrintBtn.disabled = false;
          quickPrintBtn.innerHTML = originalText;
        }
      }

      previewReceipt() {
        const preview = document.getElementById('receiptPreview');
        const receiptData = this.generateSampleReceipt();
        const decoder = new TextDecoder();
        const text = decoder.decode(receiptData);
        
        preview.textContent = text;
        preview.style.display = preview.style.display === 'none' ? 'block' : 'none';
      }

      async printViaBackend() {
        const bridgeUrl = document.getElementById('bluetoothBridgeUrl').value.trim();
        const deviceAddress = document.getElementById('bluetoothDeviceAddress').value.trim();
        const printBtn = document.getElementById('printViaBackendBtn');
        
        if (!bridgeUrl) {
          this.showMessage('Please enter Backend Bridge URL', 'error');
          return;
        }
        
        if (!deviceAddress) {
          this.showMessage('Please enter Bluetooth Device MAC Address', 'error');
          return;
        }
        
        try {
          printBtn.disabled = true;
          printBtn.innerHTML = '<span class="loading"></span> Printing via Backend...';
          this.showMessage('Sending print job to backend...', 'info');
          this.addDebugInfo('=== BACKEND BLUETOOTH PRINT ===');
          this.addDebugInfo(`Bridge URL: ${bridgeUrl}`);
          this.addDebugInfo(`Device Address: ${deviceAddress}`);
          
          const receiptData = this.generateSampleReceipt();
          this.addDebugInfo(`Receipt data size: ${receiptData.length} bytes`);
          
          const response = await fetch(bridgeUrl, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              deviceAddress: deviceAddress,
              data: Array.from(receiptData) // Convert to array for JSON
            })
          });

          const result = await response.json();

          if (result.success) {
            this.showMessage('Receipt sent to printer successfully via backend!', 'success');
            this.addDebugInfo('✓✓✓ Print job sent successfully via backend bridge!');
          } else {
            throw new Error(result.error || 'Backend returned error');
          }
          
        } catch (error) {
          this.showMessage(`Backend print failed: ${error.message}`, 'error');
          this.addDebugInfo(`✗ Backend print error: ${error.message}`);
          console.error('Backend print error:', error);
        } finally {
          printBtn.disabled = false;
          printBtn.innerHTML = '🖨️ Print via Backend Bridge';
        }
      }

      async testBackendConnection() {
        const bridgeUrl = document.getElementById('bluetoothBridgeUrl').value.trim();
        const testBtn = document.getElementById('testBackendBtn');
        
        if (!bridgeUrl) {
          this.showMessage('Please enter Backend Bridge URL', 'error');
          return;
        }
        
        try {
          testBtn.disabled = true;
          testBtn.innerHTML = '<span class="loading"></span> Testing...';
          this.showMessage('Testing backend connection...', 'info');
          
          // Try a simple GET request or health check endpoint
          const healthUrl = bridgeUrl.replace('/print', '/health').replace('/api/bluetooth/print', '/api/bluetooth/health');
          
          try {
            const response = await fetch(healthUrl, {
              method: 'GET',
              headers: {
                'Content-Type': 'application/json',
              }
            });
            
            if (response.ok) {
              this.showMessage('Backend connection successful!', 'success');
            } else {
              this.showMessage('Backend responded but endpoint may not exist', 'warning');
            }
          } catch (e) {
            // Health endpoint might not exist, try the print endpoint with minimal data
            this.showMessage('Health endpoint not found, but print endpoint may still work', 'info');
          }
          
        } catch (error) {
          this.showMessage(`Backend test failed: ${error.message}`, 'error');
        } finally {
          testBtn.disabled = false;
          testBtn.innerHTML = 'Test Backend Connection';
        }
      }

      updateStatus(status, text) {
        const indicator = document.getElementById('statusIndicator');
        const statusText = document.getElementById('statusText');
        
        indicator.className = 'status-indicator';
        if (status === 'connected') {
          indicator.classList.add('connected');
        } else if (status === 'scanning') {
          indicator.classList.add('scanning');
        }
        
        statusText.textContent = text;
      }

      showMessage(message, type) {
        const messageEl = document.getElementById('statusMessage');
        messageEl.textContent = message;
        messageEl.className = `message ${type} show`;
        
        // Auto-hide after 5 seconds for success and info messages only
        // Error messages persist until manually cleared or replaced
        if (type !== 'error') {
          setTimeout(() => {
            // Only hide if it's still the same message (not replaced)
            if (messageEl.textContent === message) {
              messageEl.classList.remove('show');
            }
          }, 5000);
        }
      }
    }

    // Initialize when page loads
    window.addEventListener('DOMContentLoaded', () => {
      window.bluetoothPrinter = new BluetoothPrinter();
    });
  </script>
</body>
</html>

