---
version: '3'

tasks:
  brewfile:
    deps:
      - :install:software:brew
    log:
      error: Encountered error while installing Homebrew software bundle defined in `.config/Brewfile`
      start: Installing Homebrew software bundle defined in `.config/Brewfile`
      success: Successfully installed Homebrew software bundle defined in `.config/Brewfile`
    cmds:
      - brew tap Homebrew/bundle
      - mkdir -p local
      - cp .config/Brewfile local/Brewfile.common
      - brew bundle install --file local/Brewfile.common
      - |
        if [ -f local/Brewfile ]; then
          brew bundle install --file local/Brewfile
        fi

  extras:
    cmds:
      - task: :install:software:gcc
      - task: :install:software:sshfs
      - task: :install:software:gcloud

  install-doctor:
    log:
      error: Error encountered while installing {{.SOFTWARE}} via https://install.doctor
      start: Ensuring {{.SOFTWARE}} is installed using Install Doctor
      success: Successfully installed `{{.SOFTWARE}}` via Install Doctor
    cmds:
      - |
        .config/log info 'Installing `{{.SOFTWARE}}` by running `curl -sS https://install.doctor/{{.SOFTWARE}} | bash`'
        curl -sS https://install.doctor/{{.SOFTWARE}} | bash
    status:
      - type {{.SOFTWARE}} &> /dev/null || [[ '{{.DOCKER_ENVIRONMENT}}' == "true" ]]

  modules:global:
    deps:
      - :install:software:volta
      - :install:software:yq
    run: once
    log:
      error: Error pre-loading NPM global packages
      start: Pre-loading NPM global packages
      success: Finished pre-loading NPM global packages
    cmds:
      - |
        PKGS="$(yq eval '.tasks[].cmds[0].vars.NPM_PACKAGE' .config/taskfiles/install/Taskfile-npm.yml | tr '\n' ' ')"
        for PKG in $PKGS; do
          if [ -f "$(echo $NODE_PATH | sed 's/^://' | sed 's/:.*//')/$PKG" ]; then
            LIST="$LIST $PKG"
          fi
        done
        if [ -n "$LIST" ]; then
          .config/log info "Installing the following NPM packages globally - $LIST"
          volta install $LIST
        fi
    status:
      - '[[ "${container:=}" == "docker" ]]'

  modules:local:
    cmds:
      - task: modules:local:init
    status:
      - '[ -n "$BUILD_DATE" ] && [ -f /.dockerenv ]'

  modules:local:init:
    deps:
      - :install:npm:{{.NPM_PROGRAM}}
      - :install:software:jq
    vars:
      PREVIOUS_DEPS:
        sh: |
          if [ -f .task/npm-deps ]; then
            cat .task/npm-deps
          else
            echo ""
          fi
    env:
      DEPS:
        sh: jq -r -S '.dependencies + .devDependencies + .optionalDependencies + .peerDependencies' package.json
      PREVIOUS_DEPS: '{{.PREVIOUS_DEPS}}'
      SEMANTIC_PYTHON_POST_INSTALL: '{{if eq .SEMANTIC_RELEASE "true"}}true{{else}}false{{end}}'
    run: when_changed
    log:
      error: Encountered error while installing local NPM dependencies
      start: Installing local NPM dependencies
      success: Successfully installed local NPM dependencies
    cmds:
      - task: tslib
      - |
        {{.NPM_PROGRAM}} config set loglevel error --location project
        {{.NPM_PROGRAM}} config set strict-peer-dependencies false --location project
      - cmd: |
          if [ "$DEPS" != "$PREVIOUS_DEPS" ] || [ ! -d node_modules ]; then
            if [ -n "$AUTO_UPDATE_NPM_PACKAGES" ]; then
              {{.NPM_PROGRAM}} update
            else
              {{.NPM_PROGRAM}} install {{if eq .NPM_PROGRAM "pnpm"}}--public-hoist-pattern *types* \
              --no-optional --loglevel error --strict-peer-dependencies false \
              --public-hoist-pattern *eslint* --public-hoist-pattern @prettier/plugin-* \
              --public-hoist-pattern *prettier-plugin-* --public-hoist-pattern *jest* {{end}}|| EXIT_CODE=$?
              if [ -n "$EXIT_CODE" ]; then
                .config/log info 'Running `{{.NPM_PROGRAM}} update` because install had non-zero exit code '"(Code $EXIT_CODE)"
                {{.NPM_PROGRAM}} update
              fi
            fi
          fi
          mkdir -p .task
          echo "$DEPS" > .task/npm-deps
        ignore_error: true
    sources:
      - package.json

  modules:local:lockfiles:
    cmds:
      - task: :install:npm:pnpm-lock-export
      - task: :install:npm:synp
      - |
        if [ ! -f package-lock.json ]; then
          pnpm-lock-export
          MOVE_PACKAGE_LOCK=true
        fi
        if [ ! -f yarn.lock ] && [ -f package-lock.json ]; then
          synp --source-file package-lock.json
          mkdir -p local
          mv yarn.lock local/yarn.lock
        fi
        if [ -n "$MOVE_PACKAGE_LOCK" ]; then
          mkdir -p local
          mv package-lock.json local/package-lock.json
        fi
    sources:
      - pnpm-lock.yaml

  modules:local:sync:
    deps:
      - modules:local
    log:
      error: Error while synchronizing `NPM_KEEP_UPDATED` packages with the latest version(s)
      start: Ensuring `NPM_KEEP_UPDATED` NPM packages are the latest version
      success: '`NPM_KEEP_UPDATED` packages are all the latest version'
    cmds:
      - |
        TMP_REFRESH="$(mktemp)"
        TMP_LIST="$(mktemp)"
        function updateAvailable() {
          LATEST="$(npm view $1 version)"
          LOCAL="$(jq -r '.version' ./node_modules/$1/package.json)"
          if ! printf '%s\n%s\n' "$LATEST" "$LOCAL" | sort -V -c > /dev/null; then
            .config/log info "Version $LATEST is available for $1 (currently version $LOCAL)"
            echo "true" > "$TMP_REFRESH"
          fi
        }
        for PATTERN in {{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}{{.NPM_KEEP_UPDATED}}{{end}}; do
           while read PATHH; do
            if [ -f "$PATHH/package.json" ]; then
              PKG="$(echo $PATHH | sed 's/.\/node_modules\///')"
              PACKAGE_LIST="$(cat "$TMP_LIST") ${PKG}@latest"
              echo "$PACKAGE_LIST" > "$TMP_LIST"
              updateAvailable "$PKG" &
            fi
          done < <(find ./node_modules/$PATTERN -maxdepth 0)
        done
        wait
        PACKAGE_LIST="$(cat "$TMP_LIST")"
        REFRESH_PACKAGES="$(cat $TMP_REFRESH)"
        if [[ "$REFRESH_PACKAGES" == 'true' ]]; then
          PACKAGE_LIST="$(echo $PACKAGE_LIST | sed 's/^.//')"
          .config/log info "Updating NPM packages configured to sync with latest version since one or more of them have an update available"
          {{.NPM_PROGRAM}} update $PACKAGE_LIST
          .config/log success 'Successfully updated to the following - `'"$PACKAGE_LIST"'`'
        else
          {{if .CLI_ARGS}}
          .config/log info '`{{.CLI_ARGS}}` is already the latest version'
          {{else}}
          .config/log info "NPM packages configured to sync with latest version are all up-to-date"
          {{end}}
        fi

  path:add:
    vars:
      UNAME:
        sh: uname
    log:
      error: Failed to modify PATH
      start: Adding `$HOME/{{.PATH_STRING}}` to the PATH in $HOME/.profile
    cmds:
      - |
        if [ '{{OS}}' == 'darwin' ] || [ '{{OS}}' == 'linux' ]; then
          # shellcheck disable=SC2016
          PATH_STRING='PATH="$HOME/{{.PATH_STRING}}:$PATH"'
          if ! grep "$PATH_STRING" "$HOME/.profile" > /dev/null; then
            echo -e "export ${PATH_STRING}\n" >> "$HOME/.profile"
            .config/log info "Updated the PATH variable to include ~/{{.PATH_STRING}} in $HOME/.profile"
          fi
        elif [[ '{{.UNAME}}' == 'CYGWIN'* ]] || [[ '{{.UNAME}}' == 'MINGW'* ]]; then
          .config/log error "Windows is not directly supported. Use WSL or Docker." && exit 1
        elif [[ "$OSTYPE" == 'freebsd'* ]]; then
          .config/log error "FreeBSD support not added yet" && exit 1
        else
          .config/log error "System type not recognized ($OSTYPE)"
        fi

  profile:add:
    log:
      error: Error modifying $HOME/.profile
      start: Adding `{{.PROFILE_STRING}}` to $HOME/.profile
      success: Successfully modified $HOME/.profile
    cmds:
      - |
        if [ '{{OS}}' == 'darwin' ] || [ '{{OS}}' == 'linux' ]; then
          # shellcheck disable=SC2016
          PROFILE_STRING='{{.PROFILE_STRING}}'
          if ! cat "$HOME/.profile" | grep "$PATH_STRING" > /dev/null; then
            echo -e "${PROFILE_STRING}\n" >> "$HOME/.profile"
            .config/log info 'Added `{{.PROFILE_STRING}}` to '"$HOME/.profile"
          fi
        elif [[ "$OSTYPE" == 'cygwin' ]] || [[ "$OSTYPE" == 'msys' ]] || [[ "$OSTYPE" == 'win32' ]]; then
          .config/log error "Windows is not directly supported. Use WSL or Docker." && exit 1
        elif [[ "$OSTYPE" == 'freebsd'* ]]; then
          .config/log error "FreeBSD support not added yet" && exit 1
        else
          .config/log error "System type not recognized"
        fi

  scoop:scan:
    deps:
      - :install:software:jq
    env:
      TMP:
        sh: mktemp
    log:
      error: Error while extracting Scoop information
      start: Extracting Scoop information
      success: Successfully extracted Scoop information
    cmds:
      - jq --arg scoops "$(jq -n '[["Project", "Description"], (inputs | ["**[" + .homepage + "](" + .homepage + ")**", .description ])]' Scoops/*.json)"
        '.scoop_var_chart = $scoops' .variables.json > "$TMP" && mv "$TMP" .variables.json

  system:upgrade:
    log:
      error: Encountered error while upgrading system
      start: Upgrading system packages
    cmds:
      - task: system:upgrade:apk
      - task: system:upgrade:apt-get
      - task: system:upgrade:dnf
      - task: system:upgrade:pacman
      - task: system:upgrade:yum
      - task: system:upgrade:macos

  system:upgrade:apk:
    cmds:
      - |
        if [ "$USER" == "root" ]; then
          .config/log info 'TODO'
        elif type sudo &> /dev/null && sudo -n true; then
          .config/log info 'TODO'
        elif type sudo &> /dev/null; then
          .config/log info 'TODO'
        else
          .config/log warn '`sudo` unavailable and user has no permissions'
        fi
    status:
      - '[ -z "$(which apk)" ]'

  system:upgrade:apt-get:
    cmds:
      - |
        if [ "$USER" == "root" ]; then
          apt-get update
          apt-get install -y {{.PACKAGE}}
        elif type sudo &> /dev/null && sudo -n true; then
          sudo apt-get update
          sudo apt -y upgrade
        elif type sudo &> /dev/null; then
          .config/log info 'Running `sudo apt-get update`'
          sudo apt-get update
          .config/log info 'Running `sudo apt -y upgrade`'
          sudo apt -y upgrade
        else
           .config/log warn '`sudo` unavailable and user has no permissions'
        fi
    status:
      - '[ -z "$(which apt-get)" ]'

  system:upgrade:dnf:
    cmds:
      - |
        if [ "$USER" == "root" ]; then
          dnf clean all
          dnf check-update
          dnf update
        elif type sudo &> /dev/null && sudo -n true; then
          sudo dnf clean all
          sudo dnf check-update
          sudo dnf update
        elif type sudo &> /dev/null; then
          .config/log info 'Running `sudo dnf clean all`'
          sudo dnf clean all
          .config/log info 'Running `sudo dnf check-update`'
          sudo dnf check-update
          .config/log info 'Running `sudo dnf update`'
          sudo dnf update
        else
           .config/log warn '`sudo` unavailable and user has no permissions'
        fi
    status:
      - '[ -z "$(which dnf)" ]'

  system:upgrade:macos:
    cmds:
      - echo "TODO Upgrade macOS system version via CLI"
    status:
      - '[ "{{OS}}" != "darwin" ]'

  system:upgrade:pacman:
    cmds:
      - |
        if [ "$USER" == "root" ]; then
          .config/log 'TODO'
        elif type sudo &> /dev/null && sudo -n true; then
          .config/log 'TODO'
        elif type sudo &> /dev/null; then
          .config/log 'TODO'
        else
           .config/log warn '`sudo` unavailable and user has no permissions'
        fi
    status:
      - '[ -z "$(which pacman)" ]'

  system:upgrade:yum:
    cmds:
      - |
        if [ "$USER" == "root" ]; then
          yum clean all
          yum update
        elif type sudo &> /dev/null && sudo -n true; then
          sudo yum clean all
          sudo yum update
        elif type sudo &> /dev/null; then
          .config/log info 'Running `sudo yum clean all`'
          sudo yum clean all
          .config/log info 'Running `sudo yum update`'
          sudo yum update
        else
           .config/log warn '`sudo` unavailable and user has no permissions'
        fi
    status:
      - '[ -z "$(which yum)" ]'

  tslib:
    vars:
      TSLIB_MSG: You can potentially optimize your bundle by setting `importHelpers` in compilerOptions
        in tsconfig.json to `true`. After importHelpers is set to true, the taskfiles will automatically
        install tslib.
    run: once
    log:
      error: Failed to probe `tslib`
      start: Checking if `tslib` is being used
    cmds:
      - |
        if [[ "$(jq -r '.dependencies.tslib' package.json)" == 'null' ]]; then
          if [ "$(jq -r '.compilerOptions.importHelpers' tsconfig.json)" != 'true' ]; then
            .config/log info '{{.TSLIB_MSG}}'
          else
            .config/log info 'Adding `tslib` to dependencies since `importHelpers` is set to true in tsconfig.json'
            TMP="$(mktemp)"
            jq '.dependencies.tslib = "latest"' package.json > "$TMP"
            mv "$TMP" package.json
          fi
        fi
    status:
      - '[ ! -f tsconfig.json ]'

  ventoy:
    cmds:
      - task: :install:ventoy:install
      - task: ventoy:init
    preconditions:
      - sh: test -d /run/media/user/Ventoy
        msg: The `/run/media/user/Ventoy` mounted USB directory must be available!

  ventoy:init:
    deps:
      - :install:ventoy:clone
      - :install:ventoy:download