#!/usr/bin/env sh
set -eu

DAY_SHIFT_DEFAULT_VERSION='0.2.23'
DAY_SHIFT_COMMAND_NAME='day-shift'
DAY_SHIFT_ORIGIN='https://tnsds.tech/downloads/'
DAY_SHIFT_VERSION=${DAY_SHIFT_VERSION:-$DAY_SHIFT_DEFAULT_VERSION}
DAY_SHIFT_INSTALL_DIR=${DAY_SHIFT_INSTALL_DIR:-$HOME/.local/day-shift}
DAY_SHIFT_BIN_DIR=${DAY_SHIFT_BIN_DIR:-$HOME/.local/bin}

log() {
  printf '[day-shift] %s\n' "$1"
}

fail() {
  printf '[day-shift] ERROR: %s\n' "$1" >&2
  exit 1
}

begin_step() {
  current_step=$1
  step_started_at=$(date +%s)
  log "$current_step..."
}

finish_step() {
  step_finished_at=$(date +%s)
  step_elapsed=$((step_finished_at - step_started_at))
  log "$current_step complete (${step_elapsed}s)."
}

download_file() {
  download_label=$1
  download_url=$2
  download_destination=$3
  begin_step "$download_label"
  log "Source: $download_url"
  if ! curl --fail --show-error --location --progress-bar --connect-timeout 15 --max-time 600 --speed-limit 1024 --speed-time 30 "$download_url" -o "$download_destination"; then
    fail "$download_label failed from $download_url. Check the network connection and DAY_SHIFT_ORIGIN, then retry."
  fi
  finish_step
}

need_command() {
  command -v "$1" >/dev/null 2>&1 || fail "Missing required command: $1"
}

version_ge_20() {
  node_version=$(node --version 2>/dev/null | sed 's/^v//')
  node_major=${node_version%%.*}
  case "$node_major" in
    ''|*[!0-9]*) return 1 ;;
  esac
  [ "$node_major" -ge 20 ]
}

log "Starting Day Shift installation (requested version: $DAY_SHIFT_VERSION)."
begin_step 'Checking prerequisites'
need_command node
need_command tar
need_command shasum
version_ge_20 || fail 'Day Shift requires system Node.js >=20.0.0 before installation changes are made.'
finish_step

resolve_script_dir() {
  script_path=$0
  while [ -L "$script_path" ]; do
    script_dir=$(CDPATH= cd -- "$(dirname -- "$script_path")" && pwd)
    link_target=$(readlink "$script_path")
    case "$link_target" in
      /*) script_path=$link_target ;;
      *) script_path=$script_dir/$link_target ;;
    esac
  done
  CDPATH= cd -- "$(dirname -- "$script_path")" && pwd
}

validate_installer_manifest_json() {
  manifest_candidate_path=$1
  manifest_candidate_source=$2
  node -e "const fs=require('fs'); const manifestPath=process.argv[1]; const manifestSource=process.argv[2]; let text=''; try { text=fs.readFileSync(manifestPath,'utf8'); } catch (error) { console.error('Failed to read downloaded installer manifest.'); process.exit(1); } try { const parsed=JSON.parse(text); if(!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('shape'); } catch (error) { const trimmed=text.trimStart(); const likelyHtml=/^<!doctype html[>\s]/i.test(trimmed) || /^<html[>\s]/i.test(trimmed); const reason=likelyHtml ? 'The download returned HTML instead of JSON.' : 'The download did not contain valid JSON.'; console.error('Downloaded installer manifest from ' + manifestSource + ' could not be parsed. ' + reason); console.error('Check that DAY_SHIFT_ORIGIN points at the published downloads directory and that installer-manifest.json is reachable there.'); process.exit(1); }" "$manifest_candidate_path" "$manifest_candidate_source" || fail 'Downloaded installer manifest is invalid.'
}

work_dir=$(mktemp -d 2>/dev/null || mktemp -d -t day-shift-install)
cleanup() { rm -rf "$work_dir"; }
trap cleanup EXIT INT TERM

script_dir=$(resolve_script_dir)
local_manifest_path="$script_dir/installer-manifest.json"
manifest_path="$work_dir/installer-manifest.json"
manifest_source=''
use_local_release_assets=false
if [ -f "$local_manifest_path" ]; then
  manifest_path="$local_manifest_path"
  manifest_source="$local_manifest_path"
  use_local_release_assets=true
  log "Using bundled installer manifest: $manifest_source"
else
  need_command curl
  manifest_url="${DAY_SHIFT_ORIGIN%/}/installer-manifest.json"
  if [ "$DAY_SHIFT_VERSION" != latest ]; then
    manifest_url="${DAY_SHIFT_ORIGIN%/}/$DAY_SHIFT_VERSION/installer-manifest.json"
  fi
  download_file 'Downloading installer manifest' "$manifest_url" "$manifest_path"
  manifest_source="$manifest_url"
fi
begin_step 'Validating installer manifest'
validate_installer_manifest_json "$manifest_path" "$manifest_source"

resolved_version=$(node -e "const fs=require('fs'); const m=JSON.parse(fs.readFileSync(process.argv[1],'utf8')); if(!m.version || m.version === 'latest') process.exit(2); process.stdout.write(m.version);" "$manifest_path")
archive_filename=$(node -e "const fs=require('fs'); const m=JSON.parse(fs.readFileSync(process.argv[1],'utf8')); const a=(m.artifacts||[]).find((item)=>item.target==='macos-linux' && item.kind==='archive' && item.runtimeModel==='system-node'); if(!a) process.exit(2); process.stdout.write(a.filename);" "$manifest_path")
archive_sha256=$(node -e "const fs=require('fs'); const m=JSON.parse(fs.readFileSync(process.argv[1],'utf8')); const a=(m.artifacts||[]).find((item)=>item.target==='macos-linux' && item.kind==='archive' && item.runtimeModel==='system-node'); if(!a || !/^[a-f0-9]{64}$/.test(a.sha256)) process.exit(2); process.stdout.write(a.sha256);" "$manifest_path")
manifest_command=$(node -e "const fs=require('fs'); const m=JSON.parse(fs.readFileSync(process.argv[1],'utf8')); if(!m.command || !m.command.installedName) process.exit(2); process.stdout.write(m.command.installedName);" "$manifest_path")
[ "$manifest_command" = "$DAY_SHIFT_COMMAND_NAME" ] || DAY_SHIFT_COMMAND_NAME=$manifest_command
finish_step
log "Resolved Day Shift $resolved_version ($archive_filename)."

archive_path="$work_dir/$archive_filename"
extract_dir="$work_dir/extract"
stage_dir="$work_dir/stage"
if [ "$use_local_release_assets" = true ]; then
  [ "$DAY_SHIFT_VERSION" = latest ] || [ "$DAY_SHIFT_VERSION" = "$resolved_version" ] || fail "Local installer assets are for version $resolved_version, but DAY_SHIFT_VERSION requested $DAY_SHIFT_VERSION."
  archive_path="$script_dir/$archive_filename"
  [ -f "$archive_path" ] || fail "Local installer expected archive '$archive_filename' next to install.sh."
  log "Using bundled release archive: $archive_path"
else
  archive_url="${DAY_SHIFT_ORIGIN%/}/$resolved_version/$archive_filename"
  download_file 'Downloading release archive' "$archive_url" "$archive_path"
fi
begin_step 'Verifying release archive checksum'
printf '%s  %s\n' "$archive_sha256" "$archive_path" | shasum -a 256 -c - >/dev/null
finish_step
begin_step 'Extracting release archive'
mkdir -p "$extract_dir" "$stage_dir"
tar -xzf "$archive_path" -C "$extract_dir"
payload_root=$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)
[ -n "$payload_root" ] || fail 'Downloaded archive did not contain an installable payload directory.'
finish_step
begin_step 'Staging release files'
cp -R "$payload_root/." "$stage_dir/"
finish_step
begin_step 'Activating installation'
mkdir -p "$DAY_SHIFT_INSTALL_DIR" "$DAY_SHIFT_BIN_DIR"
rm -rf "$DAY_SHIFT_INSTALL_DIR.previous"
if [ -e "$DAY_SHIFT_INSTALL_DIR/current" ]; then
  mv "$DAY_SHIFT_INSTALL_DIR/current" "$DAY_SHIFT_INSTALL_DIR.previous"
fi
mv "$stage_dir" "$DAY_SHIFT_INSTALL_DIR/current"
ln -sf "$DAY_SHIFT_INSTALL_DIR/current/bin/$DAY_SHIFT_COMMAND_NAME" "$DAY_SHIFT_BIN_DIR/$DAY_SHIFT_COMMAND_NAME"
finish_step
printf 'Installed Day Shift %s\n' "$resolved_version"
printf 'Executable: %s\n' "$DAY_SHIFT_BIN_DIR/$DAY_SHIFT_COMMAND_NAME"
printf 'Command: %s\n' "$DAY_SHIFT_COMMAND_NAME"
printf 'If %s is not found, run: export PATH="%s:$PATH"\n' "$DAY_SHIFT_COMMAND_NAME" "$DAY_SHIFT_BIN_DIR"
printf 'Persist PATH in your shell profile (for example ~/.zshrc or ~/.bashrc), then open a new shell or source the profile.\n'
