const http = require('http');
const fs = require('fs');
const path = require('path');

// Path to the data file. If it doesn't exist, an empty data structure will be created.
const DATA_PATH = path.join(__dirname, 'data.json');
let data;

// Load data from disk or initialize a new dataset
function loadData() {
  try {
    const raw = fs.readFileSync(DATA_PATH, 'utf8');
    data = JSON.parse(raw);
    // Ensure arrays exist
    data.properties = data.properties || [];
    data.bookings = data.bookings || [];
  } catch (err) {
    // If file doesn't exist or parse error, initialise empty dataset
    data = { properties: [], bookings: [] };
    saveData();
  }
}

// Persist data to disk
function saveData() {
  try {
    fs.writeFileSync(DATA_PATH, JSON.stringify(data, null, 2));
  } catch (err) {
    console.error('Failed to save data:', err);
  }
}

// Generate a simple unique identifier
function generateId(prefix = 'id') {
  return prefix + '-' + Date.now() + '-' + Math.floor(Math.random() * 10000);
}

// Determine MIME type based on file extension
const MIME_TYPES = {
  '.html': 'text/html; charset=UTF-8',
  '.css': 'text/css; charset=UTF-8',
  '.js': 'application/javascript; charset=UTF-8',
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.svg': 'image/svg+xml',
  '.json': 'application/json; charset=UTF-8',
  '.ico': 'image/x-icon'
};

/**
 * Serve static files from the /public directory
 */
function serveStatic(req, res) {
  const urlPath = req.url === '/' ? '/index.html' : req.url;
  const safePath = path.normalize(urlPath).replace(/^\.\.\/|^\/+|\/+/g, '');
  const filePath = path.join(__dirname, 'public', safePath);
  fs.stat(filePath, (err, stats) => {
    if (err || !stats.isFile()) {
      res.statusCode = 404;
      res.setHeader('Content-Type', 'text/plain');
      res.end('404 Not Found');
      return;
    }
    const ext = path.extname(filePath).toLowerCase();
    const mime = MIME_TYPES[ext] || 'application/octet-stream';
    res.statusCode = 200;
    res.setHeader('Content-Type', mime);
    fs.createReadStream(filePath).pipe(res);
  });
}

/**
 * Handle API requests
 */
function handleApi(req, res) {
  const method = req.method;
  const url = req.url;
  // Parse URL path without query string
  const [pathname] = url.split('?');

  // GET /api/properties
  if (method === 'GET' && pathname === '/api/properties') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify(data.properties));
    return;
  }

  // POST /api/properties
  if (method === 'POST' && pathname === '/api/properties') {
    collectRequestData(req, (err, body) => {
      if (err) {
        res.statusCode = 400;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ error: 'Invalid JSON' }));
        return;
      }
      const { name, location, price, totalRooms } = body;
      if (!name || !location || typeof price !== 'number' || typeof totalRooms !== 'number') {
        res.statusCode = 400;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ error: 'Missing or invalid property fields' }));
        return;
      }
      const newProp = {
        id: generateId('prop'),
        name: String(name),
        location: String(location),
        price: Number(price),
        totalRooms: Number(totalRooms),
        availableRooms: Number(totalRooms)
      };
      data.properties.push(newProp);
      saveData();
      res.statusCode = 201;
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify(newProp));
    });
    return;
  }

  // GET /api/bookings
  if (method === 'GET' && pathname === '/api/bookings') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify(data.bookings));
    return;
  }

  // POST /api/bookings
  if (method === 'POST' && pathname === '/api/bookings') {
    collectRequestData(req, (err, body) => {
      if (err) {
        res.statusCode = 400;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ error: 'Invalid JSON' }));
        return;
      }
      const { propertyId, rooms, guest } = body;
      const prop = data.properties.find((p) => p.id === propertyId);
      if (!prop) {
        res.statusCode = 404;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ error: 'Property not found' }));
        return;
      }
      const roomsInt = parseInt(rooms, 10);
      if (!guest || isNaN(roomsInt) || roomsInt < 1) {
        res.statusCode = 400;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ error: 'Invalid booking data' }));
        return;
      }
      if (prop.availableRooms < roomsInt) {
        res.statusCode = 400;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ error: 'Insufficient availability' }));
        return;
      }
      // Create booking
      prop.availableRooms -= roomsInt;
      const totalCost = prop.price * roomsInt;
      const booking = {
        id: generateId('book'),
        propertyId: prop.id,
        guest: String(guest),
        rooms: roomsInt,
        totalCost
      };
      data.bookings.push(booking);
      saveData();
      res.statusCode = 201;
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify(booking));
    });
    return;
  }

  // GET /api/dashboard
  if (method === 'GET' && pathname === '/api/dashboard') {
    const totalProperties = data.properties.length;
    const totalBookings = data.bookings.length;
    const totalRevenue = data.bookings.reduce((sum, b) => sum + b.totalCost, 0);
    const totalRooms = data.properties.reduce((sum, p) => sum + p.totalRooms, 0);
    const bookedRooms = data.properties.reduce(
      (sum, p) => sum + (p.totalRooms - p.availableRooms),
      0
    );
    const occupancyRate = totalRooms > 0 ? Math.round((bookedRooms / totalRooms) * 100) : 0;
    res.statusCode = 200;
    res.setHeader('Content-Type', 'application/json');
    res.end(
      JSON.stringify({
        totalProperties,
        totalBookings,
        totalRevenue,
        occupancyRate
      })
    );
    return;
  }

  // Unknown API endpoint
  res.statusCode = 404;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({ error: 'API endpoint not found' }));
}

/**
 * Collect JSON data from a POST request
 * @param {IncomingMessage} req
 * @param {Function} cb
 */
function collectRequestData(req, cb) {
  let body = '';
  req.on('data', (chunk) => {
    body += chunk;
  });
  req.on('end', () => {
    try {
      const parsed = JSON.parse(body || '{}');
      cb(null, parsed);
    } catch (err) {
      cb(err);
    }
  });
}

// Initialise data on start
loadData();

// Create the HTTP server
const server = http.createServer((req, res) => {
  // All API endpoints start with /api/
  if (req.url.startsWith('/api/')) {
    handleApi(req, res);
  } else {
    serveStatic(req, res);
  }
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`Server is running at http://localhost:${PORT}`);
});