#!/bin/sh

set -eu

OUTPUT_FILE="${1:-tree.txt}"
IGNORE_PATTERN="${2:-venv|__pycache__|.git|.gitignore|docker|node_modules|.idea}"

has_command() {
  command -v "$1" >/dev/null 2>&1
}

run_install() {
  if [ "$(id -u 2>/dev/null || echo 1)" = "0" ]; then
    "$@"
  elif has_command sudo; then
    sudo "$@"
  else
    return 1
  fi
}

try_install_tree() {
  has_command tree && return 0

  os_name="$(uname -s 2>/dev/null || echo unknown)"

  case "$os_name" in
    Darwin)
      has_command brew && brew install tree && return 0
      ;;
    Linux)
      has_command apt-get && run_install apt-get update && run_install apt-get install -y tree && return 0
      has_command dnf && run_install dnf install -y tree && return 0
      has_command yum && run_install yum install -y tree && return 0
      has_command pacman && run_install pacman -Sy --noconfirm tree && return 0
      has_command zypper && run_install zypper --non-interactive install tree && return 0
      has_command apk && run_install apk add tree && return 0
      has_command xbps-install && run_install xbps-install -Sy tree && return 0
      ;;
    FreeBSD|DragonFly)
      has_command pkg && run_install pkg install -y tree && return 0
      ;;
    OpenBSD)
      has_command pkg_add && run_install pkg_add tree && return 0
      ;;
    NetBSD)
      has_command pkgin && run_install pkgin -y install tree && return 0
      ;;
    CYGWIN*|MINGW*|MSYS*)
      has_command scoop && scoop install tree && return 0
      has_command choco && choco install tree -y && return 0
      has_command winget && winget install --id GnuWin32.Tree --exact --accept-source-agreements --accept-package-agreements && return 0
      ;;
  esac

  return 1
}

render_with_tree() {
  tree -a --noreport -I "$IGNORE_PATTERN" . >"$OUTPUT_FILE"
}

render_with_find() {
  find . -print | sort | awk -v ignore="$IGNORE_PATTERN" '
    BEGIN {
      ignored_count = split(ignore, ignored, "|")
      print "."
    }
    {
      path = $0
      sub(/^\.\//, "", path)
      if (path == "" || path == ".") {
        next
      }

      part_count = split(path, parts, "/")
      skip = 0
      for (i = 1; i <= part_count; i++) {
        for (j = 1; j <= ignored_count; j++) {
          if (parts[i] == ignored[j]) {
            skip = 1
            break
          }
        }
        if (skip) {
          break
        }
      }
      if (skip) {
        next
      }

      indent = ""
      for (i = 1; i < part_count; i++) {
        indent = indent "    "
      }
      print indent "|-- " parts[part_count]
    }
  ' >"$OUTPUT_FILE"
}

if has_command tree || try_install_tree; then
  render_with_tree
else
  echo "tree command is unavailable; using built-in fallback output." >&2
  render_with_find
fi

echo "Wrote tree structure to $OUTPUT_FILE"
