#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VERSION="0.11.0"

usage() {
  cat <<'TXT'
ClosedBit Linux Beta compiler

Commands:
  help
  check input.cbp
  compile cba input.cbp output.cba [small|chunky] [compute|graphics] [threaded] [threads COUNT] [max_memory MB] [uncapped]
  compile linux input.cbp output-folder [small|chunky] [compute|graphics] [threaded] [threads COUNT] [max_memory MB] [uncapped]
  compile library input.cbp output.cbl [small|chunky] [compute|graphics] [threaded]
  encrypt input output [key TEXT | key_file PATH]
  decrypt input output key TEXT
  decrypt input output key_file PATH

Notes:
  small and chunky cannot stack.
  ai and fps cannot stack.
  threads requires a whole-number count.
  The Runtime Package screen is forced and is not a flag.
TXT
}

die() { echo "ClosedBit Linux compiler error: $*" >&2; exit 1; }

check_source() {
  local input="$1"
  [ -f "$input" ] || die "file not found: $input"
  grep -Eq '(^|[[:space:]])fn[[:space:]]+main[[:space:]]*\(' "$input" || die "missing fn main() entry point"
  local open close
  open="$(tr -cd '{' < "$input" | wc -c | tr -d ' ')"
  close="$(tr -cd '}' < "$input" | wc -c | tr -d ' ')"
  [ "$open" = "$close" ] || die "brace count does not match"
  echo "Checker passed."
}

write_cba() {
  local input="$1"
  local output="$2"
  mkdir -p "$(dirname "$output")"
  {
    echo "CB-LINUX-CBA $VERSION"
    echo "name=$(basename "$input")"
    echo "created_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
    echo "runtime_intro=forced"
    echo "__CBP_PAYLOAD__"
    sed '/^[[:space:]]*#/d;/^[[:space:]]*$/d' "$input"
  } > "$output"
  chmod 0644 "$output"
  echo "Wrote $output"
}

write_linux_folder() {
  local input="$1"
  local output="$2"
  local stem
  stem="$(basename "$output")"
  mkdir -p "$output/package" "$output/runtime/bin" "$output/assets"
  write_cba "$input" "$output/package/$stem.cba" >/dev/null
  install -m 0755 "$SCRIPT_DIR/closedbit-runtime-linux" "$output/runtime/bin/closedbit-runtime-linux"
  cat > "$output/run.sh" <<SH
#!/usr/bin/env bash
set -euo pipefail
ROOT="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
exec "\$ROOT/runtime/bin/closedbit-runtime-linux" "\$ROOT/package/$stem.cba" "\$@"
SH
  chmod +x "$output/run.sh"
  cat > "$output/README.md" <<TXT
# ClosedBit Linux Beta Package

Run:

\`\`\`sh
./run.sh
\`\`\`

The Runtime Package screen is forced before package code starts.
TXT
  echo "Wrote $output"
}

encrypt_file() {
  local input="$1" output="$2" mode="${3:-}" key="${4:-}"
  [ -f "$input" ] || die "file not found: $input"
  if command -v openssl >/dev/null 2>&1; then
    if [ "$mode" = "key_file" ]; then [ -f "$key" ] || die "key file not found"; key="$(cat "$key")"; fi
    [ -n "$key" ] || key="$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 256)"
    openssl enc -aes-256-cbc -pbkdf2 -salt -in "$input" -out "$output" -pass "pass:$key"
  else
    cp "$input" "$output"
  fi
  echo "Wrote $output"
}

decrypt_file() {
  local input="$1" output="$2" mode="${3:-}" key="${4:-}"
  [ -f "$input" ] || die "file not found: $input"
  [ "$mode" = "key_file" ] && key="$(cat "$key")"
  command -v openssl >/dev/null 2>&1 || die "openssl is required for decrypt"
  openssl enc -d -aes-256-cbc -pbkdf2 -in "$input" -out "$output" -pass "pass:$key"
  echo "Wrote $output"
}

case "${1:-help}" in
  help|-h|--help) usage ;;
  check)
    [ "$#" -ge 2 ] || die "check requires input.cbp"
    check_source "$2"
    ;;
  compile)
    [ "$#" -ge 5 ] || die "compile requires target, input, and output"
    target="$2"; input="$3"; output="$4"
    check_source "$input" >/dev/null
    case "$target" in
      cba) write_cba "$input" "$output" ;;
      linux) write_linux_folder "$input" "$output" ;;
      library) write_cba "$input" "$output" ;;
      *) die "Linux beta supports compile cba, compile linux, and compile library" ;;
    esac
    ;;
  encrypt)
    [ "$#" -ge 3 ] || die "encrypt requires input and output"
    encrypt_file "$2" "$3" "${4:-}" "${5:-}"
    ;;
  decrypt)
    [ "$#" -ge 5 ] || die "decrypt requires input, output, key/key_file, and value"
    decrypt_file "$2" "$3" "$4" "$5"
    ;;
  *) die "unknown command '$1'. Run cbpc-linux help." ;;
esac
