///|
/// Interactive prompt implementation using async I/O.
/// 
/// This module provides the core prompt function and helper utilities.
/// Note: In MoonBit, async functions are called like regular functions -
/// they automatically wait for completion when called from another async function.
pub async fn prompt(questions : Array[Question]) -> Answer {
  let answers : Answer = {}
  for question in questions {
    let answer_value = ask_question(question)
    answers[question.question_name] = answer_value
  }
  answers
}

///|
async fn ask_question(question : Question) -> AnswerValue {
  match question.question_type {
    QuestionType::Input =>
      read_input(question.question_message, question.question_default)
    QuestionType::Confirm =>
      read_confirm(question.question_message, question.question_default)
    QuestionType::List =>
      read_list(
        question.question_message,
        question.question_choices,
        question.question_default,
      )
    QuestionType::RawList =>
      read_rawlist(
        question.question_message,
        question.question_choices,
        question.question_default,
      )
    QuestionType::Expand =>
      read_expand(question.question_message, question.question_choices)
    QuestionType::Checkbox =>
      read_checkbox(question.question_message, question.question_choices)
    QuestionType::Password => read_password(question.question_message)
    QuestionType::Editor => read_editor(question.question_message)
  }
}

///|
fn string_view_to_string(sv : StringView) -> String {
  sv.to_owned()
}

///|
async fn read_input(message : String, default : AnswerValue?) -> AnswerValue {
  let default_str = match default {
    Some(AnswerValue::StringValue(s)) => s
    _ => ""
  }

  let prompt_str = if default_str.length() > 0 {
    "\{message} (\{default_str}): "
  } else {
    "\{message}: "
  }

  @stdio.stdout.write(prompt_str)
  let input = @stdio.stdin.read_until("\n")
  let input = match input {
    Some(sv) => string_view_to_string(sv.trim())
    None => ""
  }

  if input.length() == 0 {
    AnswerValue::StringValue(default_str)
  } else {
    AnswerValue::StringValue(input)
  }
}

///|
async fn read_confirm(message : String, default : AnswerValue?) -> AnswerValue {
  let default_bool = match default {
    Some(AnswerValue::BoolValue(b)) => b
    _ => true
  }

  let default_str = if default_bool { "[Y/n]" } else { "[y/N]" }
  @stdio.stdout.write("\{message} \{default_str}: ")

  let input = @stdio.stdin.read_until("\n")
  let input = match input {
    Some(sv) => string_view_to_string(sv.trim().to_upper())
    None => ""
  }

  match input {
    "Y" | "YES" | "TRUE" | "1" => AnswerValue::BoolValue(true)
    "N" | "NO" | "FALSE" | "0" => AnswerValue::BoolValue(false)
    _ => AnswerValue::BoolValue(default_bool)
  }
}

///|
async fn read_list(
  message : String,
  choices : Array[String]?,
  default : AnswerValue?,
) -> AnswerValue {
  match choices {
    Some(choices) if choices.length() > 0 => {
      @stdio.stdout.write("\{message}\n")

      for i, choice in choices {
        let default_marker = match default {
          Some(AnswerValue::IntValue(idx)) if idx == i => " (default)"
          _ => ""
        }
        @stdio.stdout.write("  \{i + 1}. \{choice}\{default_marker}\n")
      }

      @stdio.stdout.write("Choose an option: ")
      let input = @stdio.stdin.read_until("\n")
      let input = match input {
        Some(sv) => string_view_to_string(sv.trim())
        None => ""
      }

      match safe_parse_int(input) {
        Some(num) if num >= 1 && num <= choices.length() =>
          AnswerValue::StringValue(choices[num - 1])
        _ => {
          let default_idx = match default {
            Some(AnswerValue::IntValue(idx)) if idx >= 0 &&
              idx < choices.length() => idx
            _ => 0
          }
          AnswerValue::StringValue(choices[default_idx])
        }
      }
    }
    _ => AnswerValue::StringValue("")
  }
}

///|
async fn read_rawlist(
  message : String,
  choices : Array[String]?,
  default : AnswerValue?,
) -> AnswerValue {
  match choices {
    Some(choices) if choices.length() > 0 => {
      @stdio.stdout.write("\{message}\n")

      for i, choice in choices {
        let default_marker = match default {
          Some(AnswerValue::IntValue(idx)) if idx == i => " (default)"
          _ => ""
        }
        @stdio.stdout.write("  \{i + 1}. \{choice}\{default_marker}\n")
      }

      @stdio.stdout.write("Choose an option: ")
      let input = @stdio.stdin.read_until("\n")
      let input = match input {
        Some(sv) => string_view_to_string(sv.trim())
        None => ""
      }

      match safe_parse_int(input) {
        Some(num) if num >= 1 && num <= choices.length() =>
          AnswerValue::StringValue(choices[num - 1])
        _ => {
          let default_idx = match default {
            Some(AnswerValue::IntValue(idx)) if idx >= 0 &&
              idx < choices.length() => idx
            _ => 0
          }
          AnswerValue::StringValue(choices[default_idx])
        }
      }
    }
    _ => AnswerValue::StringValue("")
  }
}

///|
async fn read_expand(message : String, choices : Array[String]?) -> AnswerValue {
  match choices {
    Some(choices) if choices.length() > 0 => {
      @stdio.stdout.write("\{message}\n")

      for i, choice in choices {
        let key = Int::unsafe_to_char(97 + i).to_string() // a, b, c, ...
        @stdio.stdout.write("  [\{key}] \{choice}\n")
      }

      @stdio.stdout.write("Choose an option: ")
      let input = @stdio.stdin.read_until("\n")
      let input = match input {
        Some(sv) => string_view_to_string(sv.trim().to_upper())
        None => ""
      }

      // Find matching key
      for i, _ in choices {
        let key = Int::unsafe_to_char(97 + i).to_string().to_upper()
        if input == key {
          return AnswerValue::StringValue(choices[i])
        }
      }

      // Default to first option
      AnswerValue::StringValue(choices[0])
    }
    _ => AnswerValue::StringValue("")
  }
}

///|
async fn read_checkbox(
  message : String,
  choices : Array[String]?,
) -> AnswerValue {
  match choices {
    Some(choices) if choices.length() > 0 => {
      @stdio.stdout.write("\{message}\n")

      for i, choice in choices {
        @stdio.stdout.write("  [ ] \{i + 1}. \{choice}\n")
      }

      @stdio.stdout.write(
        "\nEnter numbers separated by commas (e.g., 1,3,5) or press Enter for all: ",
      )
      let input = @stdio.stdin.read_until("\n")
      let input = match input {
        Some(sv) => string_view_to_string(sv.trim())
        None => ""
      }

      if input.length() == 0 {
        // Return all choices
        return AnswerValue::ArrayValue(choices)
      }

      // Parse selected indices
      let selected : Array[String] = []
      let parts = input.split(",")
      for part_sv in parts {
        let part = string_view_to_string(part_sv.trim())
        match safe_parse_int(part) {
          Some(num) if num >= 1 && num <= choices.length() =>
            selected.push(choices[num - 1])
          _ => ignore(())
        }
      }

      if selected.length() == 0 {
        AnswerValue::ArrayValue(choices)
      } else {
        AnswerValue::ArrayValue(selected)
      }
    }
    _ => AnswerValue::ArrayValue([])
  }
}

///|
async fn read_password(message : String) -> AnswerValue {
  @stdio.stdout.write("\{message}: ")
  let input = @stdio.stdin.read_until("\n")
  let input = match input {
    Some(sv) => string_view_to_string(sv.trim())
    None => ""
  }
  AnswerValue::StringValue(input)
}

///|
async fn read_editor(message : String) -> AnswerValue {
  @stdio.stdout.write(
    "\{message} (Enter your text, press Enter once to finish):\n",
  )

  // Read single line for editor
  let input = @stdio.stdin.read_until("\n")
  let input = match input {
    Some(sv) => string_view_to_string(sv.trim())
    None => ""
  }
  AnswerValue::StringValue(input)
}

///|
/// Safe wrapper for @string.parse_int that returns Int? instead of raising
pub fn safe_parse_int(s : String) -> Int? {
  Some(@string.parse_int(s)) catch {
    _ => None
  }
}

///|
/// Alias for backwards compatibility
pub fn parse_int(s : String) -> Int? {
  safe_parse_int(s)
}