#!/bin/bash
# ============================================================================
# OMARICH Connector - Installation Script for macOS
# ============================================================================
# This script installs the OMARICH Bridge for connecting GER Detect 
# and other metal detectors to omarich.codincloud.com
#
# Usage: chmod +x OMARICH-Connector.dmg.sh && ./OMARICH-Connector.dmg.sh
# ============================================================================

set -e

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

echo ""
echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║                                                            ║${NC}"
echo -e "${CYAN}║     ${GREEN}OMARICH Connector${CYAN} - Installation pour macOS          ║${NC}"
echo -e "${CYAN}║                                                            ║${NC}"
echo -e "${CYAN}║     Connectez votre GER Detect à omarich.codincloud.com   ║${NC}"
echo -e "${CYAN}║                                                            ║${NC}"
echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""

# Installation directory
INSTALL_DIR="$HOME/Applications/OMARICH-Connector"
LAUNCH_AGENT_DIR="$HOME/Library/LaunchAgents"
LAUNCH_AGENT_FILE="$LAUNCH_AGENT_DIR/com.omarich.connector.plist"

# Check for Node.js
echo -e "${BLUE}[1/5]${NC} Vérification de Node.js..."
if ! command -v node &> /dev/null; then
    echo -e "${YELLOW}⚠️  Node.js non trouvé. Installation via Homebrew...${NC}"
    
    # Check for Homebrew
    if ! command -v brew &> /dev/null; then
        echo -e "${YELLOW}Installation de Homebrew...${NC}"
        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    fi
    
    brew install node
    echo -e "${GREEN}✅ Node.js installé${NC}"
else
    NODE_VERSION=$(node -v)
    echo -e "${GREEN}✅ Node.js $NODE_VERSION détecté${NC}"
fi

# Create installation directory
echo -e "${BLUE}[2/5]${NC} Création du répertoire d'installation..."
mkdir -p "$INSTALL_DIR"
cd "$INSTALL_DIR"

# Download bridge files
echo -e "${BLUE}[3/5]${NC} Téléchargement des fichiers..."

# Create package.json
cat > package.json << 'PACKAGE_EOF'
{
  "name": "omarich-connector",
  "version": "1.0.0",
  "description": "OMARICH Bridge - Connect metal detectors to the cloud",
  "main": "bridge.js",
  "scripts": {
    "start": "node bridge.js",
    "dev": "node bridge.js --dev"
  },
  "dependencies": {
    "ws": "^8.14.2",
    "serialport": "^12.0.0"
  }
}
PACKAGE_EOF

# Create main bridge script
cat > bridge.js << 'BRIDGE_EOF'
/**
 * OMARICH Connector Bridge
 * Connects serial/USB metal detectors to the cloud platform
 */

const { SerialPort } = require('serialport');
const WebSocket = require('ws');

const CLOUD_URL = 'wss://omarich.codincloud.com/ws/bridge';
const LOCAL_PORT = 8765;

let cloudWs = null;
let localWss = null;
let serialPort = null;
let connectedClients = new Set();

// Available ports cache
let availablePorts = [];

console.log('\n╔════════════════════════════════════════════════════════════╗');
console.log('║           OMARICH Connector Bridge v1.0.0                  ║');
console.log('╚════════════════════════════════════════════════════════════╝\n');

// Scan for serial ports
async function scanPorts() {
  try {
    const ports = await SerialPort.list();
    availablePorts = ports.map(p => ({
      path: p.path,
      manufacturer: p.manufacturer || 'Unknown',
      vendorId: p.vendorId,
      productId: p.productId,
      isDetector: isLikelyDetector(p)
    }));
    
    console.log('📡 Ports série disponibles:');
    if (availablePorts.length === 0) {
      console.log('   (aucun port trouvé)');
    } else {
      availablePorts.forEach(p => {
        const indicator = p.isDetector ? '🎯' : '  ';
        console.log(`   ${indicator} ${p.path} - ${p.manufacturer}`);
      });
    }
    
    return availablePorts;
  } catch (err) {
    console.error('❌ Erreur scan ports:', err.message);
    return [];
  }
}

function isLikelyDetector(port) {
  const detectorKeywords = ['FTDI', 'Prolific', 'CH340', 'Silicon Labs', 'GER', 'OKM', 'Bluetooth'];
  const combined = `${port.manufacturer || ''} ${port.path || ''}`.toLowerCase();
  return detectorKeywords.some(k => combined.includes(k.toLowerCase()));
}

// Connect to serial port
async function connectSerial(portPath, baudRate = 9600) {
  if (serialPort && serialPort.isOpen) {
    await serialPort.close();
  }
  
  return new Promise((resolve, reject) => {
    serialPort = new SerialPort({ 
      path: portPath, 
      baudRate: baudRate,
      autoOpen: false
    });
    
    serialPort.open((err) => {
      if (err) {
        console.error(`❌ Erreur connexion ${portPath}:`, err.message);
        reject(err);
        return;
      }
      
      console.log(`✅ Connecté à ${portPath} @ ${baudRate} baud`);
      
      // Handle incoming data
      serialPort.on('data', (data) => {
        const dataStr = data.toString();
        console.log(`📥 Data: ${dataStr.trim()}`);
        
        // Broadcast to all clients
        const msg = JSON.stringify({
          type: 'serial_data',
          data: dataStr,
          port: portPath,
          timestamp: Date.now()
        });
        
        connectedClients.forEach(client => {
          if (client.readyState === WebSocket.OPEN) {
            client.send(msg);
          }
        });
        
        if (cloudWs && cloudWs.readyState === WebSocket.OPEN) {
          cloudWs.send(msg);
        }
      });
      
      serialPort.on('error', (err) => {
        console.error('❌ Erreur série:', err.message);
      });
      
      serialPort.on('close', () => {
        console.log('🔌 Port série fermé');
        serialPort = null;
      });
      
      resolve(true);
    });
  });
}

// Start local WebSocket server
function startLocalServer() {
  localWss = new WebSocket.Server({ port: LOCAL_PORT });
  
  console.log(`🌐 Serveur local démarré sur ws://localhost:${LOCAL_PORT}`);
  
  localWss.on('connection', (ws) => {
    connectedClients.add(ws);
    console.log(`👤 Client connecté (${connectedClients.size} total)`);
    
    // Send welcome message
    ws.send(JSON.stringify({
      type: 'welcome',
      version: '1.0.0',
      availablePorts: availablePorts,
      connected: serialPort && serialPort.isOpen
    }));
    
    ws.on('message', async (data) => {
      try {
        const msg = JSON.parse(data);
        await handleMessage(ws, msg);
      } catch (err) {
        console.error('❌ Message invalide:', err.message);
      }
    });
    
    ws.on('close', () => {
      connectedClients.delete(ws);
      console.log(`👤 Client déconnecté (${connectedClients.size} restants)`);
    });
  });
}

// Handle incoming messages
async function handleMessage(ws, msg) {
  console.log(`📨 Message: ${msg.type}`);
  
  switch (msg.type) {
    case 'scan':
      const ports = await scanPorts();
      ws.send(JSON.stringify({ type: 'ports', ports }));
      break;
      
    case 'connect':
      try {
        await connectSerial(msg.port, msg.baudRate || 9600);
        ws.send(JSON.stringify({ type: 'connected', port: msg.port }));
      } catch (err) {
        ws.send(JSON.stringify({ type: 'error', error: err.message }));
      }
      break;
      
    case 'disconnect':
      if (serialPort && serialPort.isOpen) {
        serialPort.close();
        ws.send(JSON.stringify({ type: 'disconnected' }));
      }
      break;
      
    case 'send':
      if (serialPort && serialPort.isOpen) {
        serialPort.write(msg.data);
        console.log(`📤 Envoyé: ${msg.data}`);
      }
      break;
      
    case 'status':
      ws.send(JSON.stringify({
        type: 'status',
        connected: serialPort && serialPort.isOpen,
        port: serialPort ? serialPort.path : null,
        availablePorts: availablePorts
      }));
      break;
  }
}

// Connect to cloud
function connectCloud() {
  console.log('☁️  Connexion au cloud...');
  
  cloudWs = new WebSocket(CLOUD_URL);
  
  cloudWs.on('open', () => {
    console.log('☁️  Connecté au cloud OMARICH');
    cloudWs.send(JSON.stringify({
      type: 'auth',
      payload: {
        deviceInfo: {
          name: require('os').hostname(),
          platform: 'macos',
          version: '1.0.0'
        }
      }
    }));
  });
  
  cloudWs.on('message', async (data) => {
    try {
      const msg = JSON.parse(data);
      if (msg.type === 'command' && serialPort && serialPort.isOpen) {
        serialPort.write(msg.data);
      }
    } catch (err) {
      // Ignore
    }
  });
  
  cloudWs.on('close', () => {
    console.log('☁️  Déconnecté du cloud, reconnexion dans 5s...');
    setTimeout(connectCloud, 5000);
  });
  
  cloudWs.on('error', (err) => {
    console.error('☁️  Erreur cloud:', err.message);
  });
}

// Check if port is in use
function checkPort(port) {
  return new Promise((resolve) => {
    const net = require('net');
    const server = net.createServer();
    server.once('error', () => resolve(false));
    server.once('listening', () => {
      server.close();
      resolve(true);
    });
    server.listen(port);
  });
}

// Kill process on port (macOS/Linux)
async function killProcessOnPort(port) {
  const { exec } = require('child_process');
  return new Promise((resolve) => {
    exec(`lsof -ti:${port} | xargs kill -9 2>/dev/null || true`, (err) => {
      setTimeout(resolve, 500); // Wait for process to die
    });
  });
}

// Main
async function main() {
  await scanPorts();
  
  // Check if port is available
  const portAvailable = await checkPort(LOCAL_PORT);
  if (!portAvailable) {
    console.log(`⚠️  Port ${LOCAL_PORT} déjà utilisé.`);
    console.log('   Tentative de libération du port...');
    await killProcessOnPort(LOCAL_PORT);
    
    // Check again
    const portNowAvailable = await checkPort(LOCAL_PORT);
    if (!portNowAvailable) {
      console.log(`❌ Impossible de libérer le port ${LOCAL_PORT}.`);
      console.log('   Une autre instance est peut-être en cours.');
      console.log('   Exécutez: lsof -ti:8765 | xargs kill -9');
      process.exit(1);
    }
    console.log('   ✅ Port libéré!');
  }
  
  startLocalServer();
  connectCloud();
  
  console.log('\n✨ OMARICH Connector prêt!');
  console.log('   Ouvrez https://omarich.codincloud.com/connector pour commencer\n');
  
  // Auto-connect to first detector if found
  const detector = availablePorts.find(p => p.isDetector);
  if (detector) {
    console.log(`🎯 Détecteur trouvé: ${detector.path}`);
    try {
      await connectSerial(detector.path);
    } catch (err) {
      console.log('   (connexion auto échouée, connectez manuellement)');
    }
  }
}

// Handle graceful shutdown
process.on('SIGINT', () => {
  console.log('\n👋 Arrêt du bridge...');
  if (serialPort && serialPort.isOpen) serialPort.close();
  if (localWss) localWss.close();
  if (cloudWs) cloudWs.close();
  process.exit(0);
});

main().catch(console.error);
BRIDGE_EOF

echo -e "${GREEN}✅ Fichiers créés${NC}"

# Install dependencies
echo -e "${BLUE}[4/5]${NC} Installation des dépendances..."
npm install --silent
echo -e "${GREEN}✅ Dépendances installées${NC}"

# Create launcher script
cat > start-omarich.command << 'LAUNCHER_EOF'
#!/bin/bash
cd "$(dirname "$0")"
echo "🚀 Démarrage OMARICH Connector..."
node bridge.js
LAUNCHER_EOF
chmod +x start-omarich.command

# Create desktop shortcut
DESKTOP_FILE="$HOME/Desktop/OMARICH Connector.command"
cat > "$DESKTOP_FILE" << EOF
#!/bin/bash
cd "$INSTALL_DIR"
node bridge.js
EOF
chmod +x "$DESKTOP_FILE"

echo -e "${BLUE}[5/5]${NC} Configuration terminée!"

echo ""
echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║                                                            ║${NC}"
echo -e "${GREEN}║     ✅ Installation terminée avec succès!                  ║${NC}"
echo -e "${GREEN}║                                                            ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "📂 Installé dans: ${CYAN}$INSTALL_DIR${NC}"
echo -e "🖥️  Raccourci créé sur le Bureau"
echo ""
echo -e "${YELLOW}Pour démarrer OMARICH Connector:${NC}"
echo -e "   Double-cliquez sur '${CYAN}OMARICH Connector${NC}' sur votre Bureau"
echo -e "   ou exécutez: ${CYAN}cd $INSTALL_DIR && npm start${NC}"
echo ""
echo -e "${BLUE}Voulez-vous démarrer OMARICH Connector maintenant? [O/n]${NC}"
read -r response
if [[ "$response" != "n" && "$response" != "N" ]]; then
    echo ""
    node bridge.js
fi
