/// Interactive Shell CLI (native target)
/// Uses native stdin/stdout for interactive input

// Native FFI for stdin/stdout

///|
extern "C" fn native_getchar() -> Int = "getchar"

///|
extern "C" fn native_putchar(c : Int) -> Int = "putchar"

///|
extern "C" fn native_fflush(stream : Int) -> Int = "fflush"

///|
fn write_string(s : String) -> Unit {
  for c in s {
    ignore(native_putchar(c.to_int()))
  }
  ignore(native_fflush(0)) // flush stdout
}

///|
fn read_line_native() -> String? {
  let result = StringBuilder::new()
  while true {
    let c = native_getchar()
    if c == -1 {
      // EOF
      if result.to_string().length() > 0 {
        return Some(result.to_string())
      } else {
        return None
      }
    }
    if c == '\n'.to_int() {
      return Some(result.to_string())
    }
    result.write_char(c.unsafe_to_char())
  }
  None
}

///|
/// Backend type for filesystem
pub(all) enum BackendType {
  Memory
  S3(String) // bucket name
  Sqlite(String) // db path
}

///|
/// Create memory filesystem backend
fn create_memory_backend() -> &@fs.FileSystem {
  @fs.Fs::default()
}

///|
/// Create S3 filesystem backend
fn create_s3_backend(bucket : String) -> &@fs.FileSystem {
  @fs.S3Backend::new(bucket)
}

///|
/// Create SQLite filesystem backend
fn create_sqlite_backend(path : String) -> &@fs.FileSystem {
  @fs.SqliteBackend::new(path)
}

///|
fn main {
  // Default to memory backend
  // In a real CLI, parse command-line arguments here
  let backend_type : BackendType = Memory
  let (fs, backend_name) : (&@fs.FileSystem, String) = match backend_type {
    Memory => (create_memory_backend(), "memory")
    S3(bucket) => (create_s3_backend(bucket), "s3://" + bucket)
    Sqlite(path) => (create_sqlite_backend(path), "sqlite://" + path)
  }
  let ctx = @posix.PosixContext::new(fs)
  let shell = @shell.Shell::new(ctx)

  write_string("MoonBit Shell\n")
  write_string("Backend: " + backend_name + "\n")
  write_string("Type 'exit' to quit\n\n")

  let mut running = true
  while running {
    write_string("$ ")
    match read_line_native() {
      None => {
        write_string("\n")
        running = false
      }
      Some(line) => {
        let trimmed = line.trim().to_string()
        if trimmed == "exit" || trimmed == "exit 0" {
          running = false
        } else if trimmed.length() > 0 {
          let result = shell.exec_line(trimmed)
          if !(result.stdout.is_empty()) {
            write_string(result.stdout)
          }
          if !(result.stderr.is_empty()) {
            write_string(result.stderr)
          }
        }
      }
    }
  }
}