const PROPERTIES_FILE = 'server.properties';

function parsePropertiesFile(raw: string): Record<string, string | number | boolean> {
  const result: Record<string, string | number | boolean> = {};

  for (const line of raw.split(/\r?\n/)) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) {
      continue;
    }

    const separator = trimmed.indexOf('=');
    if (separator === -1) {
      continue;
    }

    const key = trimmed.slice(0, separator).trim();
    const value = trimmed.slice(separator + 1).trim();
    result[key] = coercePropertyValue(value);
  }

  return result;
}

function coercePropertyValue(value: string): string | number | boolean {
  if (value === 'true') {
    return true;
  }
  if (value === 'false') {
    return false;
  }

  const asNumber = Number(value);
  if (value !== '' && !Number.isNaN(asNumber)) {
    return asNumber;
  }

  return value;
}

function serializePropertiesFile(
  properties: Record<string, string | number | boolean>,
  originalRaw: string,
): string {
  const knownKeys = new Set(Object.keys(properties));
  const lines: string[] = [];

  for (const line of originalRaw.split(/\r?\n/)) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) {
      lines.push(line);
      continue;
    }

    const separator = trimmed.indexOf('=');
    if (separator === -1) {
      lines.push(line);
      continue;
    }

    const key = trimmed.slice(0, separator).trim();
    if (knownKeys.has(key)) {
      lines.push(`${key}=${formatPropertyValue(properties[key]!)}`);
      knownKeys.delete(key);
    } else {
      lines.push(line);
    }
  }

  for (const key of knownKeys) {
    lines.push(`${key}=${formatPropertyValue(properties[key]!)}`);
  }

  return lines.join('\n');
}

function formatPropertyValue(value: string | number | boolean): string {
  if (typeof value === 'boolean') {
    return value ? 'true' : 'false';
  }

  return String(value);
}

export {
  PROPERTIES_FILE,
  parsePropertiesFile,
  serializePropertiesFile,
};
