console.log('🔄 SERVER STARTING - Version 1.0.3-relay-fix - ' + new Date().toISOString());

const express = require('express');
const cors = require('cors');
const morgan = require('morgan');
const mqtt = require('mqtt');
const aedes = require('aedes')();
const { createServer } = require('net');
const { WebSocketServer } = require('ws');
const http = require('http');
require('dotenv').config();

// Import database functions
const db = require('./database');

// =====================================================
// CONFIGURATION
// =====================================================
const PORT = process.env.PORT || 3000;
const MQTT_PORT = process.env.MQTT_PORT || 1883;
const WS_PORT = process.env.WS_PORT || 8883;

// MQTT Client Configuration (untuk connect ke HiveMQ)
const MQTT_BROKER_URL = process.env.MQTT_BROKER_URL || 'mqtt://broker.hivemq.com:1883';
const MQTT_TOPICS = {
  data: 'novil/pengering/data',
  status: 'novil/pengering/status',
  button: 'novil/pengering/button',
  control: 'novil/pengering/control'
};

// =====================================================
// EXPRESS APP
// =====================================================
const app = express();
app.use(cors());
app.use(express.json());
app.use(morgan('dev'));

// =====================================================
// DATA STORAGE (MySQL Database)
// =====================================================
let latestData = {
  suhu: 0,
  berat: 0,
  target: 0,
  relay1: false,
  relay2: false,
  relay3: false,
  relay4: false,
  status: 'DISCONNECTED',
  timestamp: new Date().toISOString()
};

// Last data received timestamp
let lastDataTimestamp = Date.now();

// Connection timeout (5 minutes = 300 seconds)
const CONNECTION_TIMEOUT = 300000;

// Check connection status periodically
setInterval(() => {
  const now = Date.now();
  const timeSinceLastData = now - lastDataTimestamp;
  
  // If no data received for more than CONNECTION_TIMEOUT, mark as disconnected
  if (timeSinceLastData > CONNECTION_TIMEOUT && latestData.status !== 'DISCONNECTED') {
    console.log('⚠️  No data received for', Math.floor(timeSinceLastData / 1000), 'seconds');
    console.log('   Marking as DISCONNECTED');
    latestData.status = 'DISCONNECTED';
    // Optionally reset relay states
    latestData.relay1 = false;
    latestData.relay2 = false;
    latestData.relay3 = false;
    latestData.relay4 = false;
  }
}, 5000); // Check every 5 seconds

// Initialize database on startup
(async () => {
  try {
    console.log('🔄 Initializing database connection...');
    const connected = await db.testConnection();
    if (connected) {
      console.log('✅ Database connected, initializing tables...');
      await db.initDatabase();
      // Load latest data from database
      try {
        const latest = await db.getLatestSensorData();
        if (latest) {
          latestData = {
            suhu: latest.suhu,
            berat: latest.berat,
            target: latest.target,
            relay1: latest.relay1,
            relay2: latest.relay2,
            relay3: latest.relay3,
            relay4: latest.relay4,
            status: latest.status,
            timestamp: latest.timestamp
          };
          console.log('✅ Latest data loaded from database');
        }
      } catch (loadError) {
        console.warn('⚠️  Could not load latest data:', loadError.message);
      }
    } else {
      console.warn('⚠️  Running without database connection');
    }
  } catch (error) {
    console.error('❌ Database initialization error:', error.message);
    console.warn('⚠️  Continuing without database...');
  }
})();

// =====================================================
// MQTT CLIENT (Connect to HiveMQ)
// =====================================================
console.log('🔄 Connecting to MQTT Broker:', MQTT_BROKER_URL);

const mqttClient = mqtt.connect(MQTT_BROKER_URL, {
  clientId: `backend_${Math.random().toString(16).slice(2, 10)}`,
  clean: true,
  connectTimeout: 4000,
  reconnectPeriod: 1000,
  keepalive: 60
});

mqttClient.on('connect', () => {
  console.log('✅ Connected to MQTT Broker (HiveMQ)');
  
  // Subscribe to all topics
  mqttClient.subscribe([
    MQTT_TOPICS.data,
    MQTT_TOPICS.status,
    MQTT_TOPICS.button,
    MQTT_TOPICS.control
  ], (err) => {
    if (err) {
      console.error('❌ Failed to subscribe:', err);
    } else {
      console.log('✅ Subscribed to topics:');
      console.log('   -', MQTT_TOPICS.data);
      console.log('   -', MQTT_TOPICS.status);
      console.log('   -', MQTT_TOPICS.button);
      console.log('   -', MQTT_TOPICS.control);
    }
  });
});

mqttClient.on('error', (error) => {
  console.error('❌ MQTT Client Error:', error.message);
});

mqttClient.on('reconnect', () => {
  console.log('🔄 Reconnecting to MQTT Broker...');
});

mqttClient.on('offline', () => {
  console.warn('⚠️  MQTT Client offline');
});

mqttClient.on('message', async (topic, message) => {
  const msg = message.toString();
  console.log(`📨 MQTT Message received:`);
  console.log(`   Topic: ${topic}`);
  console.log(`   Message: ${msg}`);
  
  // =====================================================
  // TOPIC: novil/pengering/data
  // Format: {"suhu":28.5,"berat":450,"target":315,"relay1":true,"relay2":true,"relay3":true,"relay4":false}
  // =====================================================
  if (topic === MQTT_TOPICS.data) {
    try {
      const data = JSON.parse(msg);
      
      // Debug: log parsed data
      console.log('📦 Parsed MQTT data:', JSON.stringify(data, null, 2));
      console.log('   Data type check:', {
        relay1_type: typeof data.relay1,
        relay1_value: data.relay1,
        relay2_type: typeof data.relay2,
        relay2_value: data.relay2,
        relay3_type: typeof data.relay3,
        relay3_value: data.relay3,
        relay4_type: typeof data.relay4,
        relay4_value: data.relay4
      });
      
      // Get current time in WIB (UTC+7)
      const now = new Date();
      const wibTime = new Date(now.getTime() + (7 * 60 * 60 * 1000));
      
      // Update last data timestamp
      lastDataTimestamp = Date.now();
      
      // Helper function to map ESP32 status to backend status
      const mapStatus = (esp32Status) => {
        if (!esp32Status) return latestData.status;
        const statusMap = {
          'SELESAI': 'COMPLETED',
          'BERJALAN': 'RUNNING',
          'SCANNING': 'SCANNING',
          'READY': 'READY',
          'CONNECTED': 'CONNECTED',
          'ERROR': 'ERROR'
        };
        return statusMap[esp32Status.toUpperCase()] || esp32Status;
      };

      // Update latestData dengan data dari ESP32 (termasuk status relay)
      // Use explicit check for undefined/null to handle false values correctly
      latestData = {
        suhu: data.suhu || 0,
        berat: data.berat || 0,
        target: data.target || 0,
        relay1: (data.relay1 !== undefined && data.relay1 !== null) ? Boolean(data.relay1) : latestData.relay1,
        relay2: (data.relay2 !== undefined && data.relay2 !== null) ? Boolean(data.relay2) : latestData.relay2,
        relay3: (data.relay3 !== undefined && data.relay3 !== null) ? Boolean(data.relay3) : latestData.relay3,
        relay4: (data.relay4 !== undefined && data.relay4 !== null) ? Boolean(data.relay4) : latestData.relay4,
        status: mapStatus(data.status), // Map ESP32 status to backend status
        timestamp: wibTime.toISOString()
      };
      
      console.log('   Final latestData relay values:', {
        relay1: latestData.relay1,
        relay2: latestData.relay2,
        relay3: latestData.relay3,
        relay4: latestData.relay4,
        status: latestData.status
      });
      
      // Save to database
      try {
        await db.insertSensorData(latestData);
        console.log('✅ Data saved to MySQL database');
      } catch (dbError) {
        console.error('❌ Failed to save to database:', dbError.message);
      }
      
      console.log('✅ Data updated:', latestData);
    } catch (e) {
      console.error('❌ Error parsing data:', e);
    }
  }
  
  // =====================================================
  // TOPIC: novil/pengering/status
  // Format: "ESP32 CONNECTED", "PENGERINGAN DIMULAI", dll
  // =====================================================
  if (topic === MQTT_TOPICS.status) {
    // Update status di latestData
    if (msg.includes('ESP32 CONNECTED')) {
      latestData.status = 'CONNECTED';
    } else if (msg.includes('PENGERINGAN SIAP')) {
      latestData.status = 'READY';
    } else if (msg.includes('PENGERINGAN DIMULAI')) {
      latestData.status = 'RUNNING';
    } else if (msg.includes('PENGERINGAN BERJALAN')) {
      latestData.status = 'RUNNING';
    } else if (msg.includes('PENGERINGAN SELESAI')) {
      latestData.status = 'COMPLETED';
    } else if (msg.includes('SCAN BERAT')) {
      latestData.status = 'SCANNING';
    } else if (msg.includes('DHT ERROR')) {
      latestData.status = 'ERROR';
    }
    
    // Save to database
    try {
      await db.insertStatusHistory(msg);
      console.log('✅ Status saved to MySQL database');
    } catch (dbError) {
      console.error('❌ Failed to save status to database:', dbError.message);
    }
    console.log('📊 Status:', msg);
  }
  
  // =====================================================
  // TOPIC: novil/pengering/button
  // Format: "BUTTON PRESSED", "START_BUTTON", "RESET_BUTTON"
  // =====================================================
  if (topic === MQTT_TOPICS.button) {
    console.log('🔘 Button Event:', msg);
    
    // Save button event to status history
    try {
      await db.insertStatusHistory(`BUTTON: ${msg}`);
      console.log('✅ Button event saved to MySQL database');
    } catch (dbError) {
      console.error('❌ Failed to save button event:', dbError.message);
    }
  }
  
  // =====================================================
  // TOPIC: novil/pengering/control
  // Format: "STATUS:HEATER_ON", "HEATER_ON", "FAN_OFF", dll
  // =====================================================
  if (topic === MQTT_TOPICS.control) {
    console.log('🎛️  Control Message:', msg);
    
    // Jika pesan dimulai dengan "STATUS:", ini adalah feedback dari ESP32
    if (msg.startsWith('STATUS:')) {
      const statusMsg = msg.replace('STATUS:', '');
      console.log('📊 Relay Status Update:', statusMsg);
      
      // Update relay state di latestData
      if (statusMsg === 'HEATER_ON') latestData.relay1 = true;
      else if (statusMsg === 'HEATER_OFF') latestData.relay1 = false;
      else if (statusMsg === 'FAN_ON') latestData.relay2 = true;
      else if (statusMsg === 'FAN_OFF') latestData.relay2 = false;
      else if (statusMsg === 'EXHAUST_ON') latestData.relay3 = true;
      else if (statusMsg === 'EXHAUST_OFF') latestData.relay3 = false;
      
      // Save status update to status_history
      try {
        await db.insertStatusHistory(`RELAY: ${statusMsg}`);
        console.log('✅ Relay status saved to status_history');
      } catch (dbError) {
        console.error('❌ Failed to save relay status:', dbError.message);
      }
      
      // Save juga ke control_commands dengan source ESP32
      try {
        await db.insertControlCommand(statusMsg, 'ESP32');
        console.log('✅ Relay status saved to control_commands');
      } catch (dbError) {
        console.error('❌ Failed to save to control_commands:', dbError.message);
      }
    } else {
      // Ini adalah command dari API/Flutter, simpan ke control_commands
      try {
        await db.insertControlCommand(msg, 'MQTT');
        console.log('✅ Control command saved to control_commands');
      } catch (dbError) {
        console.error('❌ Failed to save control command:', dbError.message);
      }
    }
  }
});

// =====================================================
// MQTT BROKER (AEDES)
// =====================================================
const mqttServer = createServer(aedes.handle);

// MQTT Event Handlers
aedes.on('client', (client) => {
  console.log(`📱 Client Connected: ${client.id}`);
});

aedes.on('clientDisconnect', (client) => {
  console.log(`📴 Client Disconnected: ${client.id}`);
});

aedes.on('publish', async (packet, client) => {
  if (client) {
    const topic = packet.topic;
    const message = packet.payload.toString();
    
    console.log(`📨 Message from ${client.id}:`);
    console.log(`   Topic: ${topic}`);
    console.log(`   Message: ${message}`);
    
    // =====================================================
    // TOPIC: novil/pengering/data
    // Format: {"suhu":28.5,"berat":450,"target":315,"relay1":true,"relay2":true,"relay3":true,"relay4":false}
    // =====================================================
    if (topic === 'novil/pengering/data') {
      try {
        const data = JSON.parse(message);
        
        // Update last data timestamp
        lastDataTimestamp = Date.now();
        
        // Helper function to map ESP32 status to backend status
        const mapStatus = (esp32Status) => {
          if (!esp32Status) return latestData.status;
          const statusMap = {
            'SELESAI': 'COMPLETED',
            'BERJALAN': 'RUNNING',
            'SCANNING': 'SCANNING',
            'READY': 'READY',
            'CONNECTED': 'CONNECTED',
            'ERROR': 'ERROR'
          };
          return statusMap[esp32Status.toUpperCase()] || esp32Status;
        };
        
        // Update latestData dengan data dari ESP32 (termasuk status relay)
        // Use explicit check for undefined/null to handle false values correctly
        latestData = {
          suhu: data.suhu || 0,
          berat: data.berat || 0,
          target: data.target || 0,
          relay1: (data.relay1 !== undefined && data.relay1 !== null) ? Boolean(data.relay1) : latestData.relay1,
          relay2: (data.relay2 !== undefined && data.relay2 !== null) ? Boolean(data.relay2) : latestData.relay2,
          relay3: (data.relay3 !== undefined && data.relay3 !== null) ? Boolean(data.relay3) : latestData.relay3,
          relay4: (data.relay4 !== undefined && data.relay4 !== null) ? Boolean(data.relay4) : latestData.relay4,
          status: mapStatus(data.status), // Map ESP32 status to backend status
          timestamp: new Date().toISOString()
        };
        
        // Save to database
        try {
          await db.insertSensorData(latestData);
          console.log('✅ Data saved to database');
        } catch (dbError) {
          console.error('❌ Failed to save to database:', dbError.message);
        }
        
        console.log('✅ Data updated:', latestData);
      } catch (e) {
        console.error('❌ Error parsing data:', e);
      }
    }
    
    // =====================================================
    // TOPIC: novil/pengering/status
    // Format: "ESP32 CONNECTED", "PENGERINGAN DIMULAI", dll
    // =====================================================
    if (topic === 'novil/pengering/status') {
      // Update status di latestData
      if (message.includes('ESP32 CONNECTED')) {
        latestData.status = 'CONNECTED';
      } else if (message.includes('PENGERINGAN SIAP')) {
        latestData.status = 'READY';
      } else if (message.includes('PENGERINGAN DIMULAI')) {
        latestData.status = 'RUNNING';
      } else if (message.includes('PENGERINGAN BERJALAN')) {
        latestData.status = 'RUNNING';
      } else if (message.includes('PENGERINGAN SELESAI')) {
        latestData.status = 'COMPLETED';
      } else if (message.includes('SCAN BERAT')) {
        latestData.status = 'SCANNING';
      } else if (message.includes('DHT ERROR')) {
        latestData.status = 'ERROR';
      }
      
      // Save to database
      try {
        await db.insertStatusHistory(message);
        console.log('✅ Status saved to database');
      } catch (dbError) {
        console.error('❌ Failed to save status to database:', dbError.message);
      }
      console.log('📊 Status:', message);
    }
    
    // =====================================================
    // TOPIC: novil/pengering/button
    // Format: "BUTTON PRESSED", "START_BUTTON", "RESET_BUTTON"
    // =====================================================
    if (topic === 'novil/pengering/button') {
      console.log('🔘 Button Event:', message);
      
      // Save button event to status history
      try {
        await db.insertStatusHistory(`BUTTON: ${message}`);
      } catch (dbError) {
        console.error('❌ Failed to save button event:', dbError.message);
      }
    }
    
    // =====================================================
    // TOPIC: novil/pengering/control
    // Format: "STATUS:HEATER_ON", "HEATER_ON", "FAN_OFF", dll
    // =====================================================
    if (topic === 'novil/pengering/control') {
      console.log('🎛️  Control Message:', message);
      
      // Jika pesan dimulai dengan "STATUS:", ini adalah feedback dari ESP32
      if (message.startsWith('STATUS:')) {
        const statusMsg = message.replace('STATUS:', '');
        console.log('📊 Relay Status Update:', statusMsg);
        
        // Update relay state di latestData
        if (statusMsg === 'HEATER_ON') latestData.relay1 = true;
        else if (statusMsg === 'HEATER_OFF') latestData.relay1 = false;
        else if (statusMsg === 'FAN_ON') latestData.relay2 = true;
        else if (statusMsg === 'FAN_OFF') latestData.relay2 = false;
        else if (statusMsg === 'EXHAUST_ON') latestData.relay3 = true;
        else if (statusMsg === 'EXHAUST_OFF') latestData.relay3 = false;
        
        // Save status update to status_history
        try {
          await db.insertStatusHistory(`RELAY: ${statusMsg}`);
          console.log('✅ Relay status saved to database');
        } catch (dbError) {
          console.error('❌ Failed to save relay status:', dbError.message);
        }
      } else {
        // Ini adalah command dari API/Flutter, simpan ke control_commands
        try {
          await db.insertControlCommand(message, 'MQTT');
          console.log('✅ Control command saved to database');
        } catch (dbError) {
          console.error('❌ Failed to save control command:', dbError.message);
        }
      }
    }
  }
});

aedes.on('subscribe', (subscriptions, client) => {
  console.log(`📬 Client ${client.id} subscribed to:`, subscriptions.map(s => s.topic).join(', '));
});

// Start MQTT Server (only if not in production or if explicitly enabled)
if (process.env.ENABLE_MQTT_BROKER === 'true') {
  mqttServer.listen(MQTT_PORT, () => {
    console.log(`🚀 MQTT Broker running on port ${MQTT_PORT}`);
  }).on('error', (err) => {
    console.warn(`⚠️  MQTT Broker failed to start on port ${MQTT_PORT}:`, err.message);
    console.log('ℹ️  MQTT Broker disabled. Use external MQTT broker (e.g., HiveMQ)');
  });
} else {
  console.log('ℹ️  MQTT Broker disabled (use external MQTT broker like HiveMQ)');
}

// =====================================================
// WEBSOCKET MQTT (for web clients)
// =====================================================
const httpServer = http.createServer();
const ws = new WebSocketServer({ server: httpServer });

ws.on('connection', (socket) => {
  const stream = require('websocket-stream')(socket);
  aedes.handle(stream);
  console.log('🌐 WebSocket MQTT client connected');
});

if (process.env.ENABLE_MQTT_BROKER === 'true') {
  httpServer.listen(WS_PORT, () => {
    console.log(`🌐 WebSocket MQTT running on port ${WS_PORT}`);
  }).on('error', (err) => {
    console.warn(`⚠️  WebSocket MQTT failed to start on port ${WS_PORT}:`, err.message);
  });
} else {
  console.log('ℹ️  WebSocket MQTT disabled');
}

// =====================================================
// REST API ENDPOINTS
// =====================================================

// Health check
app.get('/', (req, res) => {
  res.json({
    status: 'OK',
    message: 'Pengering Ikan Backend Server - MQTT Client Enabled',
    version: '1.0.3-relay-fix',  // Updated version with relay boolean fix
    uptime: process.uptime(),
    timestamp: new Date().toISOString()
  });
});

// Initialize database tables (manual trigger)
app.post('/api/database/init', async (req, res) => {
  try {
    const connected = await db.testConnection();
    if (!connected) {
      return res.status(500).json({
        success: false,
        message: 'Database connection failed'
      });
    }
    
    const initialized = await db.initDatabase();
    if (initialized) {
      res.json({
        success: true,
        message: 'Database tables initialized successfully'
      });
    } else {
      res.status(500).json({
        success: false,
        message: 'Failed to initialize database tables'
      });
    }
  } catch (error) {
    res.status(500).json({
      success: false,
      message: 'Error initializing database',
      error: error.message
    });
  }
});

// Test database connection
app.get('/api/database/test', async (req, res) => {
  try {
    const connected = await db.testConnection();
    if (connected) {
      res.json({
        success: true,
        message: 'Database connection successful'
      });
    } else {
      res.status(500).json({
        success: false,
        message: 'Database connection failed'
      });
    }
  } catch (error) {
    res.status(500).json({
      success: false,
      message: 'Error testing database connection',
      error: error.message
    });
  }
});

// Post sensor data from ESP32
app.post('/api/data/sensor', async (req, res) => {
  try {
    const { suhu, berat, target, relay1, relay2, relay3, relay4, status } = req.body;
    
    // Validate data
    if (suhu === undefined || berat === undefined) {
      return res.status(400).json({
        success: false,
        message: 'Suhu and berat are required'
      });
    }
    
    // Update latest data
    latestData = {
      suhu: suhu || 0,
      berat: berat || 0,
      target: target || 0,
      relay1: relay1 || false,
      relay2: relay2 || false,
      relay3: relay3 || false,
      relay4: relay4 || false,
      status: status || 'UNKNOWN',
      timestamp: new Date().toISOString()
    };
    
    // Save to database
    try {
      await db.insertSensorData(latestData);
      console.log('✅ Data from ESP32 saved to database');
    } catch (dbError) {
      console.error('❌ Failed to save to database:', dbError.message);
    }
    
    res.json({
      success: true,
      message: 'Data received successfully',
      data: latestData
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: 'Error processing sensor data',
      error: error.message
    });
  }
});

// Post status from ESP32
app.post('/api/status', async (req, res) => {
  try {
    const { message } = req.body;
    
    if (!message) {
      return res.status(400).json({
        success: false,
        message: 'Status message is required'
      });
    }
    
    // Save to database
    try {
      await db.insertStatusHistory(message);
      console.log('✅ Status from ESP32 saved:', message);
    } catch (dbError) {
      console.error('❌ Failed to save status to database:', dbError.message);
    }
    
    res.json({
      success: true,
      message: 'Status received successfully'
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: 'Error processing status',
      error: error.message
    });
  }
});

// Get latest data
app.get('/api/data/latest', (req, res) => {
  res.json({
    success: true,
    data: latestData
  });
});

// Get data history
app.get('/api/data/history', async (req, res) => {
  try {
    const limit = parseInt(req.query.limit) || 50;
    const history = await db.getSensorDataHistory(limit);
    
    res.json({
      success: true,
      count: history.length,
      data: history
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: 'Failed to get data history',
      error: error.message
    });
  }
});

// Get status history
app.get('/api/status/history', async (req, res) => {
  try {
    const limit = parseInt(req.query.limit) || 50;
    const history = await db.getStatusHistory(limit);
    
    res.json({
      success: true,
      count: history.length,
      data: history
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: 'Failed to get status history',
      error: error.message
    });
  }
});

// Publish control command
app.post('/api/control', async (req, res) => {
  const { command } = req.body;
  
  if (!command) {
    return res.status(400).json({
      success: false,
      message: 'Command is required'
    });
  }
  
  // Valid commands (sesuai dengan ESP32)
  const validCommands = [
    'HEATER_ON', 'HEATER_OFF',
    'FAN_ON', 'FAN_OFF',
    'LAMP_ON', 'LAMP_OFF',
    'EXHAUST_ON', 'EXHAUST_OFF',
    'START',  // Mulai pengeringan
    'RESET'   // Reset ke mode ready
  ];
  
  if (!validCommands.includes(command)) {
    return res.status(400).json({
      success: false,
      message: 'Invalid command',
      validCommands: validCommands
    });
  }
  
  // Save command to database
  try {
    await db.insertControlCommand(command, 'API');
  } catch (dbError) {
    console.error('❌ Failed to save command to database:', dbError.message);
  }
  
  // Publish to MQTT (HiveMQ)
  mqttClient.publish(MQTT_TOPICS.control, command, { qos: 1 }, (err) => {
    if (err) {
      return res.status(500).json({
        success: false,
        message: 'Failed to publish command',
        error: err.message
      });
    }
    
    console.log(`✅ Command published to MQTT: ${command}`);
    res.json({
      success: true,
      message: 'Command sent successfully',
      command: command
    });
  });
});

// Get statistics
app.get('/api/stats', async (req, res) => {
  try {
    const dbStats = await db.getStatistics();
    
    res.json({
      success: true,
      stats: {
        mqttConnected: mqttClient.connected,
        ...dbStats,
        latestData: latestData,
        uptime: process.uptime(),
        timestamp: new Date().toISOString()
      }
    });
  } catch (error) {
    res.json({
      success: true,
      stats: {
        mqttConnected: mqttClient.connected,
        latestData: latestData,
        uptime: process.uptime(),
        timestamp: new Date().toISOString(),
        databaseError: error.message
      }
    });
  }
});

// Clear history
app.delete('/api/history/clear', async (req, res) => {
  try {
    await db.clearOldData(0); // Clear all data
    
    res.json({
      success: true,
      message: 'History cleared successfully'
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: 'Failed to clear history',
      error: error.message
    });
  }
});

// 404 handler
app.use((req, res) => {
  res.status(404).json({
    success: false,
    message: 'Endpoint not found'
  });
});

// Error handler
app.use((err, req, res, next) => {
  console.error('❌ Error:', err);
  res.status(500).json({
    success: false,
    message: 'Internal server error',
    error: err.message
  });
});

// =====================================================
// START EXPRESS SERVER
// =====================================================
const server = app.listen(PORT, '0.0.0.0', () => {
  console.log('');
  console.log('='.repeat(60));
  console.log('🚀 PENGERING IKAN BACKEND SERVER v1.0.3-relay-fix');
  console.log('='.repeat(60));
  console.log(`📡 REST API: http://0.0.0.0:${PORT}`);
  console.log(`🔗 MQTT Broker: ${MQTT_BROKER_URL}`);
  console.log(`📊 MQTT Status: ${mqttClient.connected ? '✅ Connected' : '⏳ Connecting...'}`);
  console.log('');
  console.log('📋 Available Endpoints:');
  console.log('   GET  /                      - Health check');
  console.log('   GET  /api/data/latest       - Get latest sensor data');
  console.log('   GET  /api/data/history      - Get data history');
  console.log('   GET  /api/status/history    - Get status history');
  console.log('   GET  /api/stats             - Get server statistics');
  console.log('   POST /api/control           - Send control command');
  console.log('   POST /api/data/sensor       - Post sensor data (ESP32)');
  console.log('   POST /api/status            - Post status (ESP32)');
  console.log('   DELETE /api/history/clear   - Clear history');
  console.log('');
  console.log('📡 MQTT Topics:');
  console.log('   Subscribe:', MQTT_TOPICS.data);
  console.log('   Subscribe:', MQTT_TOPICS.status);
  console.log('   Subscribe:', MQTT_TOPICS.button);
  console.log('   Publish:  ', MQTT_TOPICS.control);
  console.log('');
  console.log('✅ Server is ready!');
  console.log('='.repeat(60));
});

server.on('error', (error) => {
  console.error('❌ Server error:', error);
  if (error.code === 'EADDRINUSE') {
    console.error(`Port ${PORT} is already in use`);
  }
  process.exit(1);
});

// =====================================================
// GRACEFUL SHUTDOWN
// =====================================================
process.on('SIGTERM', () => {
  console.log('🛑 SIGTERM received, shutting down gracefully...');
  
  // Close MQTT client
  if (mqttClient) {
    mqttClient.end(() => {
      console.log('✅ MQTT client closed');
    });
  }
  
  // Close HTTP server
  server.close(() => {
    console.log('✅ HTTP server closed');
  });
  
  // Close MQTT broker if enabled
  if (process.env.ENABLE_MQTT_BROKER === 'true') {
    mqttServer.close(() => {
      console.log('✅ MQTT server closed');
    });
    httpServer.close(() => {
      console.log('✅ WebSocket server closed');
    });
  }
  
  process.exit(0);
});

process.on('SIGINT', () => {
  console.log('🛑 SIGINT received, shutting down gracefully...');
  
  // Close MQTT client
  if (mqttClient) {
    mqttClient.end(() => {
      console.log('✅ MQTT client closed');
    });
  }
  
  // Close HTTP server
  server.close(() => {
    console.log('✅ HTTP server closed');
  });
  
  process.exit(0);
});

process.on('uncaughtException', (error) => {
  console.error('❌ Uncaught Exception:', error);
  process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('❌ Unhandled Rejection at:', promise, 'reason:', reason);
  process.exit(1);
});
