#Requires -Version 7.0

# Determine the path to this script (we'll use this to figure out relative positions of other files)
$SOURCE = $MyInvocation.MyCommand.Path

# Check if verbose mode is enabled (GitHub Actions debug mode or explicit flag)
$VERBOSE_MODE = $env:RUNNER_DEBUG -eq "1" -or $env:QUARTO_TEST_VERBOSE -eq "true"

# ------ Setting all the paths required

if ($VERBOSE_MODE) {
  Write-Host "> Setting all the paths required..."
}

# Tests folder 
# e.g quarto-cli/tests folder
$SCRIPT_PATH = Split-Path -Path $SOURCE

# Project folder
# e.g quarto-cli project folder 
$QUARTO_ROOT = Split-Path $SCRIPT_PATH

# Source folder
# e.g quarto-cli/src folder
$QUARTO_SRC_DIR= Join-Path $QUARTO_ROOT "src"

# .sh version has source $SCRIPT_PATH/../package/scripts/common/utils.sh for configure.sh requirements
# but configure.cmd does not need it

# Quarto binary folder
# e.g quarto-cli/package/dist/bin
$QUARTO_BIN_PATH = Join-Path $QUARTO_ROOT "package" "dist" "bin"
# Deno binary in tools/
$QUARTO_DENO = Join-Path $QUARTO_BIN_PATH "tools" "x86_64" "deno.exe"

# Shared resource folder
# e.g quarto-cli/src/resources
$QUARTO_SHARE_PATH = Join-Path $QUARTO_ROOT "src" "resources"


# ----- Restoring tests environnment ---------

If ( $null -eq $Env:GITHUB_ACTION -and $null -eq $Env:QUARTO_TESTS_NO_CONFIG ) {
  Write-Host "> Checking and configuring environment for tests"
  . ./configure-test-env.ps1
}

# ----- Preparing running tests ------------

if ($VERBOSE_MODE) {
  Write-Host "> Preparing running tests..."
}

# Exporting some variables with paths as env var required for running quarto
$Env:QUARTO_ROOT = $QUARTO_ROOT
$Env:QUARTO_BIN_PATH = $QUARTO_BIN_PATH
$Env:QUARTO_SHARE_PATH = $QUARTO_SHARE_PATH

# Activated debug mode by default for stack trace
$Env:QUARTO_DEBUG = "true"

# Set DENO_DIR to cache location (respects QUARTO_DENO_DIR override)
If ($null -eq $Env:QUARTO_DENO_DIR) {
  $Env:DENO_DIR = Join-Path $QUARTO_BIN_PATH "deno_cache"
} Else {
  $Env:DENO_DIR = $Env:QUARTO_DENO_DIR
}

# Preparing running Deno with default arguments

$QUARTO_IMPORT_MAP_ARG="--importmap=$(Join-Path $QUARTO_SRC_DIR "import_map.json")"
$QUARTO_DENO_OPTIONS="--config test-conf.json --v8-flags=--enable-experimental-regexp-engine,--max-old-space-size=8192,--max-heap-size=8192 --unstable-kv --unstable-ffi --no-lock --allow-all --check"

# Parsing argument passed to the script

# We Don't use `param()` or `$args` - instead, we do our own argument parsing because
# PowerShell quietly strips -- from the list of arguments and `--` is need for Deno to pass argument to the script
# Code adapted from: https://stackoverflow.com/questions/56750826/how-to-use-dash-argument-in-powershell
if ( $MyInvocation.Line -eq "" ) {
  # when script is ran from a child process using -F
  # e.g pwsh -F ./run-tests.ps1 smoke/smoke-all.test.ts -- docs\smoke-all\2023\02\08\4272.qmd
  $customArgs = $MyInvocation.UnboundArguments
} elseif ($MyInvocation.InvocationName -eq '&') {
  # when script is called via call operator from another script
  # e.g & .\run-tests.ps1 @args
  # Use UnboundArguments directly as it contains the actual arguments passed
  $customArgs = $MyInvocation.UnboundArguments
} elseif ($MyInvocation.Line -match "^[.] '[^']*'") {
  # when script is ran from a child process using -command
  # e.g pwsh -command ". 'run-tests.ps1' smoke/smoke-all.test.ts -- docs\smoke-all\2023\02\08\4272.qmd"
  # This is what happens on GHA when using 'run: |' and 'shell: pwsh'
  $argList = ($MyInvocation.Line -replace "^[.] '[^']*'\s*" -split '[;|]')[0].Trim()
  # Extract the argument list from the invocation command line.

  # Use Invoke-Expression with a Write-Output call to parse the raw argument list,
  # performing evaluation and splitting it into an array:
  $customArgs = $argList ? @(Invoke-Expression "Write-Output -- $argList") : @()
} else {
  # When script is called from main process
  # e.g ./run-tests.ps1 smoke/smoke-all.test.ts -- docs\smoke-all\2023\02\08\4272.qmd
  $argList = ($MyInvocation.Line -replace ('^.*' + [regex]::Escape($MyInvocation.InvocationName)) -split '[;|]')[0].Trim()
  # Extract the argument list from the invocation command line.

  # Use Invoke-Expression with a Write-Output call to parse the raw argument list,
  # performing evaluation and splitting it into an array:
  $customArgs = $argList ? @(Invoke-Expression "Write-Output -- $argList") : @()
}

# Check if keep-outputs mode is enabled and filter it from arguments
$KEEP_OUTPUTS = $false
$FILTERED_CUSTOM_ARGS = @()
foreach ($arg in $customArgs) {
  if ($arg -eq "--keep-outputs" -or $arg -eq "-k") {
    $KEEP_OUTPUTS = $true
  } else {
    $FILTERED_CUSTOM_ARGS += $arg
  }
}
$customArgs = $FILTERED_CUSTOM_ARGS

if ($KEEP_OUTPUTS) {
  $env:QUARTO_TEST_KEEP_OUTPUTS = "true"
  Write-Host "> Keep outputs mode enabled - test artifacts will not be deleted"
}

## Short version syntax to run smoke-all.test.ts
## Only use if different than ./run-test.ps1 ./smoke/smoke-all.test.ts
If ($customArgs[0] -notlike "*smoke-all.test.ts") {

  $SMOKE_ALL_TEST_FILE="./smoke/smoke-all.test.ts"
  # Check file argument
  $SMOKE_ALL_FILES=@()
  $TESTS_TO_RUN=@()

  ForEach ($file in $customArgs) {
    $filename=$(Split-Path -Path $file -Leaf)

    If ($filename -match "^[^_].*[.]qmd$" -Or $filename -match "^[^_].*[.]ipynb$" -Or $filename -match "^[^_].*[.]md$") {
      $SMOKE_ALL_FILES+=$file
    } elseif ($file -Like "*.ts") {
      $TESTS_TO_RUN+=$file
    } else {
      Write-Host -ForegroundColor red "#### ERROR"
      Write-Host -ForegroundColor red "Only .ts, or .qmd, .md and .ipynb passed to smoke-all.test.ts are accepted (file starting with _ are ignored)."
      Write-Host -ForegroundColor red "####"
      Exit 1
    }
  }

  If ($SMOKE_ALL_FILES.count -ne 0) {
    if ($TESTS_TO_RUN.count -ne 0) {
      Write-Host "#### WARNING"
      Write-Host "  When passing .qmd, .md and/or .ipynb, only ./smoke/smoke-all.test.ts will be run. Other tests files are ignored."
      Write-Host "  Ignoring $($TESTS_TO_RUN -join ' ')"
      Write-Host "####"
    }
    $TESTS_TO_RUN= @("${SMOKE_ALL_TEST_FILE}", "--") + $SMOKE_ALL_FILES
  }

} else {
  $TESTS_TO_RUN=$customArgs
}

# ---- Running tests with Deno -------

$DENO_ARGS = @()
$DENO_ARGS += "test"
$DENO_ARGS += -split $QUARTO_DENO_OPTIONS
# Allow to pass some more options - empty by default
If ($QUARTO_DENO_EXTRA_OPTIONS -ne $null) { 
  $DENO_ARGS += -split $QUARTO_DENO_EXTRA_OPTIONS
}
$DENO_ARGS += -split $QUARTO_IMPORT_MAP_ARG
$DENO_ARGS += $TESTS_TO_RUN

# Activate python virtualenv
# set QUARTO_TESTS_FORCE_NO_VENV env var to not activate the virtualenv located in the project
# QUARTO_TESTS_FORCE_NO_PIPENV is there for backward compatibility
If ($null -eq $Env:QUARTO_TESTS_FORCE_NO_VENV -and $null -ne $Env:QUARTO_TESTS_FORCE_NO_PIPENV) {
  $Env:QUARTO_TESTS_FORCE_NO_VENV = $Env:QUARTO_TESTS_FORCE_NO_PIPENV
}
If ($null -eq $Env:QUARTO_TESTS_FORCE_NO_VENV) {
  # Save possible activated virtualenv for later restauration
  $OLD_VIRTUAL_ENV=$VIRTUAL_ENV
  if ($VERBOSE_MODE) {
    Write-Host "> Activating virtualenv from .venv for Python tests in Quarto"
  }
  . $(Join-Path $QUARTO_ROOT "tests" ".venv/Scripts/activate.ps1")
  if ($VERBOSE_MODE) {
    Write-Host "> Using Python from " -NoNewline; Write-Host "$((gcm python).Source)" -ForegroundColor Blue;
    Write-Host "> VIRTUAL_ENV: " -NoNewline; Write-Host "$($env:VIRTUAL_ENV)" -ForegroundColor Blue;
  }
  $quarto_venv_activated = $true
}


if ($VERBOSE_MODE) {
  Write-Host "> Running tests with `"$QUARTO_DENO $DENO_ARGS`" "
}

& $QUARTO_DENO $DENO_ARGS

$SUCCESS = $?
$DENO_EXIT_CODE = $LASTEXITCODE

# Add Coverage handling

If($quarto_venv_activated) {
  if ($VERBOSE_MODE) {
    Write-Host "> Exiting virtualenv activated for tests"
  }
  deactivate
  if ($VERBOSE_MODE) {
    Write-Host "> Using Python from " -NoNewline; Write-Host "$((gcm python).Source)" -ForegroundColor Blue;
    Write-Host "> VIRTUAL_ENV: " -NoNewline; Write-Host "$($env:VIRTUAL_ENV)" -ForegroundColor Blue;
  }
  Remove-Variable quarto_venv_activated
}
If($null -ne $OLD_VIRTUAL_ENV) {
  if ($VERBOSE_MODE) {
    Write-Host "> Reactivating original virtualenv"
  }
  . "$OLD_VIRTUAL_ENV/Scripts/activate.ps1"
  if ($VERBOSE_MODE) {
    Write-Host "> New Python from " -NoNewline; Write-Host "$((gcm python).Source)" -ForegroundColor Blue;
    Write-Host "> VIRTUAL_ENV: " -NoNewline; Write-Host "$($env:VIRTUAL_ENV)" -ForegroundColor Blue;
  }
  Remove-Variable OLD_VIRTUAL_ENV
}

Exit $DENO_EXIT_CODE
