import fs from 'fs';
import path from 'path';

type EnvSchema = Record<string, 'string' | 'number' | 'boolean'>;

interface LoadOptions {
  path?: string;
  allowPartial?: boolean;
  defaults?: Record<string, any>;
}

function parseValue(value: string, type: string) {
  switch (type) {
    case 'number':
      const n = Number(value);
      if (isNaN(n)) throw new Error(`Invalid number: ${value}`);
      return n;
    case 'boolean':
      if (value === 'true') return true;
      if (value === 'false') return false;
      throw new Error(`Invalid boolean: ${value}`);
    case 'string':
    default:
      return value;
  }
}

export function loadEnv(schema: EnvSchema, options: LoadOptions = {}) {
  const envPath = options.path || path.resolve(process.cwd(), '.env');
  const allowPartial = options.allowPartial ?? false;
  const defaults = options.defaults || {};

  if (!fs.existsSync(envPath)) throw new Error(`.env file not found at ${envPath}`);
  const raw = fs.readFileSync(envPath, 'utf8');

  const lines = raw.split('\n');
  const envRaw: Record<string, string> = {};
  for (const line of lines) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;
    const [key, ...rest] = trimmed.split('=');
    envRaw[key] = rest.join('=').trim();
  }

  const finalEnv: Record<string, any> = {};
  for (const key in schema) {
    const expectedType = schema[key];
    const rawValue = envRaw[key] ?? defaults[key];
    if (rawValue === undefined) {
      if (!allowPartial) throw new Error(`Missing required env variable: ${key}`);
      continue;
    }
    finalEnv[key] = parseValue(rawValue, expectedType);
  }

  return finalEnv;
}