const RESERVED_SUBDOMAINS = new Set([
  'www',
  'api',
  'admin',
  'app',
  'dashboard',
  'localhost',
]);

function badRequest(message) {
  const error = new Error(message);
  error.code = 400;
  throw error;
}

function normalizeSubdomain(value) {
  if (typeof value !== 'string') {
    return '';
  }

  return value
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9-]+/g, '-')
    .replace(/-{2,}/g, '-')
    .replace(/^-+|-+$/g, '');
}

function isReservedSubdomain(value) {
  return RESERVED_SUBDOMAINS.has(value) || value.startsWith('127-');
}

function validateSubdomainOrThrow(value, { allowEmpty = false } = {}) {
  const normalized = normalizeSubdomain(value);

  if (!normalized) {
    if (allowEmpty) {
      return normalized;
    }

    badRequest('A valid tenant subdomain is required.');
  }

  if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(normalized)) {
    badRequest('Tenant subdomains may only contain lowercase letters, numbers, and hyphens.');
  }

  if (isReservedSubdomain(normalized)) {
    badRequest(`The subdomain '${normalized}' is reserved and cannot be used.`);
  }

  return normalized;
}

function getRequestHostname(reqOrHost) {
  if (!reqOrHost) {
    return '';
  }

  if (typeof reqOrHost === 'string') {
    return reqOrHost;
  }

  return (
    reqOrHost.get?.('x-forwarded-host') ||
    reqOrHost.get?.('host') ||
    reqOrHost.hostname ||
    ''
  );
}

function extractTenantSubdomain(hostname) {
  const cleanHost = String(hostname || '')
    .split(',')[0]
    .trim()
    .split(':')[0]
    .toLowerCase();

  if (!cleanHost || cleanHost === 'localhost' || cleanHost.startsWith('127.')) {
    return null;
  }

  const segments = cleanHost.split('.').filter(Boolean);

  if (cleanHost.endsWith('.localhost')) {
    if (segments.length < 2) {
      return null;
    }

    return validateSubdomainOrThrow(segments[0]);
  }

  if (segments.length < 3) {
    return null;
  }

  return validateSubdomainOrThrow(segments[0]);
}

module.exports = {
  RESERVED_SUBDOMAINS,
  normalizeSubdomain,
  isReservedSubdomain,
  validateSubdomainOrThrow,
  getRequestHostname,
  extractTenantSubdomain,
};
