#!/bin/bash

# Fix AirwavePBX Services

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

echo "========================================="
echo "Fixing AirwavePBX Services"
echo "========================================="
echo

# Stop services first
echo -e "${BLUE}[INFO]${NC} Stopping services..."
pm2 stop all

# Fix the API server to handle AMI connection failures gracefully
echo -e "${BLUE}[INFO]${NC} Fixing API server..."
cat > /opt/airwavepbx/api/server-fixed.js << 'EOF'
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const sqlite3 = require('sqlite3').verbose();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const AMI = require('asterisk-manager');
const { Server } = require('socket.io');
const http = require('http');
const path = require('path');
require('dotenv').config({ path: '/etc/airwavepbx/airwavepbx.env' });

const app = express();
const server = http.createServer(app);
const io = new Server(server, {
  cors: {
    origin: process.env.DOMAIN ? `http://${process.env.DOMAIN}` : '*',
    methods: ['GET', 'POST']
  }
});

// Middleware
app.use(cors());
app.use(bodyParser.json());

// Database setup
const db = new sqlite3.Database(process.env.DATABASE_PATH || '/var/lib/airwavepbx/data/airwavepbx.db');

// Initialize database
db.serialize(() => {
  // Users table
  db.run(`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT UNIQUE NOT NULL,
    password TEXT NOT NULL,
    email TEXT,
    role TEXT DEFAULT 'user',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  )`);

  // Extensions table
  db.run(`CREATE TABLE IF NOT EXISTS extensions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    extension TEXT UNIQUE NOT NULL,
    name TEXT NOT NULL,
    context TEXT DEFAULT 'internal',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  )`);

  // Create default admin user if not exists
  const defaultPassword = bcrypt.hashSync('admin', 10);
  db.run(`INSERT OR IGNORE INTO users (username, password, email, role) 
          VALUES ('admin', ?, 'admin@localhost', 'admin')`, [defaultPassword], (err) => {
    if (!err) {
      console.log('Default admin user created');
    }
  });
});

// AMI Connection with error handling
let ami = null;
let amiConnected = false;

function connectAMI() {
  try {
    ami = new AMI({
      port: 5038,
      host: 'localhost',
      username: 'airwavepbx',
      password: process.env.AMI_PASSWORD || 'changeme',
      keepConnected: true,
      reconnect: true,
      reconnectTimeout: 3000
    });

    ami.on('connect', () => {
      console.log('Connected to Asterisk AMI');
      amiConnected = true;
    });

    ami.on('error', (err) => {
      console.error('AMI Error:', err.message);
      amiConnected = false;
    });

    ami.on('disconnect', () => {
      console.log('Disconnected from AMI');
      amiConnected = false;
    });

    ami.on('reconnection', () => {
      console.log('Reconnecting to AMI...');
    });

    ami.on('event', (evt) => {
      io.emit('asterisk-event', evt);
    });

    // Attempt connection
    ami.connect((err) => {
      if (err) {
        console.error('Failed to connect to AMI:', err.message);
        console.log('API will continue without AMI connection');
        amiConnected = false;
      }
    });
  } catch (err) {
    console.error('Error setting up AMI:', err.message);
    console.log('API will continue without AMI connection');
    amiConnected = false;
  }
}

// Auth middleware
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.sendStatus(401);
  }

  jwt.verify(token, process.env.JWT_SECRET || 'default-secret', (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};

// Routes
app.get('/api', (req, res) => {
  res.json({ 
    status: 'ok', 
    version: '2.0.0',
    ami: amiConnected ? 'connected' : 'disconnected'
  });
});

// Auth routes
app.post('/api/auth/login', async (req, res) => {
  const { username, password } = req.body;
  
  db.get('SELECT * FROM users WHERE username = ?', [username], async (err, user) => {
    if (err) return res.status(500).json({ error: 'Database error' });
    if (!user) return res.status(400).json({ error: 'Invalid credentials' });
    
    const validPassword = await bcrypt.compare(password, user.password);
    if (!validPassword) return res.status(400).json({ error: 'Invalid credentials' });
    
    const token = jwt.sign(
      { id: user.id, username: user.username, role: user.role },
      process.env.JWT_SECRET || 'default-secret',
      { expiresIn: '24h' }
    );
    
    res.json({ token, user: { id: user.id, username: user.username, role: user.role } });
  });
});

// Extension routes
app.get('/api/extensions', authenticateToken, (req, res) => {
  db.all('SELECT * FROM extensions', (err, rows) => {
    if (err) return res.status(500).json({ error: 'Database error' });
    res.json(rows);
  });
});

app.post('/api/extensions', authenticateToken, (req, res) => {
  const { extension, name, context } = req.body;
  
  db.run('INSERT INTO extensions (extension, name, context) VALUES (?, ?, ?)',
    [extension, name, context || 'internal'],
    function(err) {
      if (err) return res.status(500).json({ error: 'Database error' });
      res.json({ id: this.lastID, extension, name, context: context || 'internal' });
    }
  );
});

app.delete('/api/extensions/:id', authenticateToken, (req, res) => {
  db.run('DELETE FROM extensions WHERE id = ?', [req.params.id], (err) => {
    if (err) return res.status(500).json({ error: 'Database error' });
    res.json({ success: true });
  });
});

// Dashboard stats
app.get('/api/dashboard/stats', authenticateToken, (req, res) => {
  const stats = {
    totalExtensions: 0,
    activeCalls: 0,
    systemStatus: amiConnected ? 'online' : 'offline',
    uptime: process.uptime()
  };
  
  db.get('SELECT COUNT(*) as count FROM extensions', (err, row) => {
    if (!err) stats.totalExtensions = row.count;
    res.json(stats);
  });
});

// System routes
app.get('/api/system/status', authenticateToken, (req, res) => {
  res.json({
    asterisk: amiConnected ? 'connected' : 'disconnected',
    database: 'connected',
    uptime: process.uptime()
  });
});

// Start server
const PORT = process.env.API_PORT || 3001;
server.listen(PORT, () => {
  console.log(`API server running on port ${PORT}`);
  // Try to connect to AMI after server starts
  connectAMI();
});

// WebSocket server on port 8080
const wsServer = http.createServer();
const wsIo = new Server(wsServer, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST']
  }
});

wsServer.listen(8080, () => {
  console.log('WebSocket server running on port 8080');
});
EOF

# Copy the fixed server
cp /opt/airwavepbx/api/server-fixed.js /opt/airwavepbx/api/server.js

# Fix the Next.js start command in package.json
echo -e "${BLUE}[INFO]${NC} Fixing Next.js configuration..."
cd /opt/airwavepbx

# Remove standalone output from next.config.js if it exists
if [ -f next.config.mjs ]; then
    sed -i '/output:.*standalone/d' next.config.mjs
fi

# Update PM2 ecosystem file
echo -e "${BLUE}[INFO]${NC} Updating PM2 configuration..."
cat > /opt/airwavepbx/ecosystem.config.js << 'EOF'
module.exports = {
  apps: [
    {
      name: 'airwavepbx-frontend',
      script: 'npm',
      args: 'start',
      cwd: '/opt/airwavepbx',
      env_file: '/etc/airwavepbx/airwavepbx.env',
      error_file: '/var/log/airwavepbx/frontend-error.log',
      out_file: '/var/log/airwavepbx/frontend-out.log',
      merge_logs: true,
      max_restarts: 10,
      min_uptime: 5000,
      env: {
        PORT: 3000,
        NODE_ENV: 'production'
      }
    },
    {
      name: 'airwavepbx-api',
      script: 'api/server.js',
      cwd: '/opt/airwavepbx',
      env_file: '/etc/airwavepbx/airwavepbx.env',
      error_file: '/var/log/airwavepbx/api-error.log',
      out_file: '/var/log/airwavepbx/api-out.log',
      merge_logs: true,
      max_restarts: 10,
      min_uptime: 5000,
      env: {
        API_PORT: 3001,
        NODE_ENV: 'production'
      }
    }
  ]
};
EOF

# Clear logs
echo -e "${BLUE}[INFO]${NC} Clearing old logs..."
pm2 flush

# Start services
echo -e "${BLUE}[INFO]${NC} Starting services..."
pm2 delete all 2>/dev/null || true
pm2 start ecosystem.config.js

# Wait for services to start
sleep 5

# Check status
echo
echo -e "${BLUE}[INFO]${NC} Checking service status..."
pm2 status

# Test connections
echo
echo -e "${BLUE}[INFO]${NC} Testing connections..."
echo -n "Frontend (port 3000): "
if curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 | grep -q "200\|302"; then
    echo -e "${GREEN}OK${NC}"
else
    echo -e "${RED}FAILED${NC}"
fi

echo -n "API (port 3001): "
if curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/api | grep -q "200"; then
    echo -e "${GREEN}OK${NC}"
else
    echo -e "${RED}FAILED${NC}"
fi

# Check if we can access through domain
echo
echo -e "${BLUE}[INFO]${NC} Testing domain access..."
source /etc/airwavepbx/airwavepbx.env
echo "Testing http://$DOMAIN ..."
if curl -s -o /dev/null -w "%{http_code}" -H "Host: $DOMAIN" http://localhost | grep -q "200\|301\|302"; then
    echo -e "${GREEN}[SUCCESS]${NC} Domain is accessible!"
    echo
    echo "You should now be able to access: http://$DOMAIN"
else
    echo -e "${YELLOW}[WARNING]${NC} Could not access through domain"
    echo "Check your DNS settings and firewall"
fi

echo
echo "========================================="
echo "Service Fix Complete"
echo "========================================="
echo
echo "Next steps:"
echo "1. Access your PBX at: http://$DOMAIN"
echo "2. Login with: admin / admin"
echo "3. For SSL: sudo ./ssl-fix.sh"
echo
echo "Monitor logs with: pm2 logs"