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

const PORT = process.env.PORT || 3000;
const ROOT = path.join(__dirname, 'out');

const MIME = {
  '.html': 'text/html; charset=utf-8',
  '.css': 'text/css; charset=utf-8',
  '.js': 'application/javascript; charset=utf-8',
  '.json': 'application/json; charset=utf-8',
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.gif': 'image/gif',
  '.svg': 'image/svg+xml',
  '.ico': 'image/x-icon',
  '.webp': 'image/webp',
  '.woff': 'font/woff',
  '.woff2': 'font/woff2',
  '.ttf': 'font/ttf',
  '.txt': 'text/plain; charset=utf-8',
  '.xml': 'application/xml; charset=utf-8',
  '.webmanifest': 'application/manifest+json',
  '.map': 'application/octet-stream',
};

function resolvePath(url) {
  const decoded = decodeURIComponent(url).split('?')[0];
  if (decoded === '/') return path.join(ROOT, 'index.html');

  const ext = path.extname(decoded);
  if (ext) return path.join(ROOT, decoded);

  const asHtml = path.join(ROOT, decoded + '.html');
  if (fs.existsSync(asHtml)) return asHtml;

  const asIndex = path.join(ROOT, decoded, 'index.html');
  if (fs.existsSync(asIndex)) return asIndex;

  return path.join(ROOT, decoded + '.html');
}

function sendFile(res, filePath, statusCode) {
  const ext = path.extname(filePath);
  const ct = MIME[ext] || 'application/octet-stream';
  const isHtml = ext === '.html';

  fs.readFile(filePath, (err, data) => {
    if (err) {
      res.writeHead(500);
      res.end('Internal Server Error');
      return;
    }
    res.writeHead(statusCode, {
      'Content-Type': ct,
      'Cache-Control': isHtml ? 'no-cache' : 'public, max-age=31536000, immutable',
    });
    res.end(data);
  });
}

function serve(req, res) {
  const filePath = path.normalize(resolvePath(req.url));

  if (!filePath.startsWith(ROOT)) {
    res.writeHead(403);
    res.end('Forbidden');
    return;
  }

  fs.access(filePath, fs.constants.F_OK, (err) => {
    if (err) {
      const four04 = path.join(ROOT, '404.html');
      fs.access(four04, fs.constants.F_OK, (err2) => {
        if (err2) {
          sendFile(res, path.join(ROOT, 'index.html'), 200);
        } else {
          sendFile(res, four04, 404);
        }
      });
      return;
    }
    sendFile(res, filePath, 200);
  });
}

const server = http.createServer(serve);
server.listen(PORT, () => {
  console.log(`Static server running at http://localhost:${PORT} (serving ${ROOT})`);
});
