'use strict';

const fs = require('fs');

const VALID_DB_TYPES = ['postgresql', 'mysql', 'oracle', 'sqlite'];

const DB_TYPE_TO_DIALECT = {
  postgresql: 'postgres',
  mysql: 'mysql',
  oracle: 'oracle',
  sqlite: 'sqlite'
};

const REQUIRED_FIELDS = {
  postgresql: ['DB_HOST', 'DB_PORT', 'DB_NAME', 'DB_USER', 'DB_PASSWORD'],
  mysql: ['DB_HOST', 'DB_PORT', 'DB_NAME', 'DB_USER', 'DB_PASSWORD'],
  // Oracle: service name dicek terpisah di bawah karena boleh DB_SERVICE_NAME
  // ATAU DB_NAME (selaras dengan runtime + introspector legacy yang memakai
  // DB_NAME sebagai service name pada connect string //host:port/<service>).
  oracle: ['DB_HOST', 'DB_PORT', 'DB_USER', 'DB_PASSWORD'],
  sqlite: ['DB_FILE']
};

function parseConfig(content) {
  if (typeof content !== 'string') {
    throw new Error('parseConfig: content must be a string');
  }

  const result = {};
  const lines = content.split(/\r?\n/);

  for (let i = 0; i < lines.length; i++) {
    const raw = lines[i];
    const line = raw.trim();
    if (line === '') continue;
    if (line.startsWith('#')) continue;

    const eqIndex = line.indexOf('=');
    if (eqIndex === -1) {
      throw new Error(`Invalid config line ${i + 1}: '${raw}'. Expected format: KEY=VALUE`);
    }

    const key = line.slice(0, eqIndex).trim();
    const value = line.slice(eqIndex + 1).trim();

    if (key === '') {
      throw new Error(`Invalid config line ${i + 1}: '${raw}'. Key cannot be empty`);
    }

    result[key] = value;
  }

  return result;
}

function loadConfig(filePath) {
  if (!filePath || typeof filePath !== 'string') {
    throw new Error('loadConfig: filePath must be a non-empty string');
  }

  if (!fs.existsSync(filePath)) {
    throw new Error(`Config file not found: ${filePath}`);
  }

  const content = fs.readFileSync(filePath, 'utf8');
  const raw = parseConfig(content);

  if (!raw.DB_TYPE) {
    throw new Error(
      `DB_TYPE not found in config file '${filePath}'. ` +
        `Add DB_TYPE=${VALID_DB_TYPES.join('|')} to the config.`
    );
  }

  const dbType = raw.DB_TYPE;
  if (!VALID_DB_TYPES.includes(dbType)) {
    throw new Error(
      `Invalid DB_TYPE '${dbType}' in config file '${filePath}'. ` +
        `Supported: ${VALID_DB_TYPES.join(', ')}`
    );
  }

  const required = REQUIRED_FIELDS[dbType];
  const missing = required.filter((field) => !raw[field]);
  if (missing.length > 0) {
    throw new Error(
      `Config file '${filePath}' missing required fields for ${dbType}: ${missing.join(', ')}`
    );
  }

  // Oracle service name boleh datang dari DB_SERVICE_NAME atau DB_NAME.
  if (dbType === 'oracle' && !raw.DB_SERVICE_NAME && !raw.DB_NAME) {
    throw new Error(
      `Config file '${filePath}' missing required fields for oracle: DB_SERVICE_NAME (atau DB_NAME)`
    );
  }

  const dialect = DB_TYPE_TO_DIALECT[dbType];
  const config = { dialect };

  if (raw.DB_HOST !== undefined) config.host = raw.DB_HOST;
  if (raw.DB_PORT !== undefined) {
    const port = parseInt(raw.DB_PORT, 10);
    if (Number.isNaN(port)) {
      throw new Error(
        `Invalid DB_PORT '${raw.DB_PORT}' in config file '${filePath}'. Must be an integer.`
      );
    }
    config.port = port;
  }
  if (raw.DB_NAME !== undefined) config.database = raw.DB_NAME;
  if (raw.DB_USER !== undefined) config.user = raw.DB_USER;
  if (raw.DB_PASSWORD !== undefined) config.password = raw.DB_PASSWORD;
  // serviceName: utamakan DB_SERVICE_NAME, fallback ke DB_NAME (Oracle).
  if (raw.DB_SERVICE_NAME !== undefined) {
    config.serviceName = raw.DB_SERVICE_NAME;
  } else if (dbType === 'oracle' && raw.DB_NAME !== undefined) {
    config.serviceName = raw.DB_NAME;
  }
  if (raw.DB_FILE !== undefined) config.file = raw.DB_FILE;

  return config;
}

module.exports = { loadConfig, parseConfig };
