#!/bin/zsh

# Adapted from https://github.com/basecamp/omarchy/tree/master?tab=readme-ov-file

function usage() {
  cat <<EOF
Generates a '.desktop' file for a web application, so that it
can act as a stand alone application and launched from an application
launcher.

USAGE: install-webapp [-n <name>] [-u <url>] [-i <icon>] [-e <exec-cmd>] [-m <mime-types>] [-f <file>] [-h] [args...]

OPTIONS:
  -n | --name:        The name of the application.
  -u | --url:         The url used to launch the application.
  -i | --icon:        The icon for the application.
  -e | --exec:        Custom execution command (optional).
  -m | --mime-types:  MIME-types for the application (optional).
  -f | --file:        Install from a spec in a json file.
  -h | --help:        Show usage information.

EXAMPLES:

If no options or arguments are supplied, then it will start an interactive session that prompts for the
values.

  $ install-webapp

Calling the app with named arguments:

  $ install-webapp \\
      --name "My Awesome App" \\
      --url "https://awesome.com" \\
      --icon "https://awesome.com/assets/icon.png"

Using a json file as input:

  $ install-webapp --file myapp.json

It is also possible to use only positional arguments with out their key. They can be passed in the order as 
they're listed.

  $ install-webapp "My Awesome App" \\
      "https://awesome.com" \\
      "https://awesome.com/assets/icon.png"

NOTES:  

The icon option can either be a url where we will download a png from or a local file. Local files
can either be the full path to the file or a file name of an icon located in '~/.local/share/applications/icons/'.

Interactive sessions do not give the option to use a custom execution command or supply the
MIME types, which are less frequently used options.

If using a json spec file, all keys are the same as their option name, except for mime-types use 'mime_types' as the
key in the json object. Although the 'exec' and 'mime_types' are not required in the spec file. An common json spec
file example would look like:

{
  "name": "My Awesome App",
  "url": "https://awesome.com",
  "icon: "https://awesome.com/assets/icon.png"
}

EOF
}

declare -a app_name
declare -a app_url
declare -a icon_ref
declare -a custom_exec # Optional custom exec command
declare -a mime_types  # Optional mime types
declare -a help_flag
declare -a file_mode
declare INTERACTIVE_MODE=false
SCRIPTS="${SCRIPTS}"

if [[ -z "$SCRIPTS" ]]; then
  echo "SCRIPTS not set"
  echo "using ~/.local/scripts"
  SCRIPTS=$HOME/.local/scripts
fi

zparseopts -D -F -K -- \
  {n,-name}:=app_name \
  {u,-url}:=app_url \
  {i,-icon}:=icon_ref \
  {e,-exec}:=custom_exec \
  {m,-mime-types}:=mime_types \
  {f,-file}:=file_mode \
  {h,-help}=help_flag

[ ${#help_flag[@]} -gt 0 ] && usage && exit 0

# If passed in as positional arguments, without flags.
[ -n "$1" ] && app_name+=("$1")
[ -n "$2" ] && app_url+=("$2")
[ -n "$3" ] && icon_ref+=("$3")
[ -n "$4" ] && custom_exec+=("$4")
[ -n "$5" ] && mime_types+=("$5")

# If passed in a json spec file.
if [[ -n "$file_mode" ]]; then
  file=$(cat ${file_mode[-1]})
  app_name+=$(echo $file | jq -r '.name')
  app_url+=$(echo $file | jq -r '.url')
  icon_ref+=$(echo $file | jq -r '.icon')
  custom_exec+=$(echo $file | jq -r '.exec')
  mime_types+=$(echo $file | jq -r '.mime_types')
fi

# Check if proper arguments were passed in. Start interactive mode if not.
if [[ -z "$app_name[-1]" || -z "$app_url[-1]" || -z "$icon_ref[-1]" ]]; then
  echo -e "\e[32mLet's create a new web app you can start with the app launcher.\n\e[0m"
  app_name+=($(gum input --prompt "Name> " --placeholder "My favorite web app"))
  app_url+=($(gum input --prompt "URL> " --placeholder "https://example.com"))
  icon_ref+=($(gum input --prompt "Icon URL> " --placeholder "See https://dashboardicons.com (must use PNG!)"))
  INTERACTIVE_MODE=true
else
  INTERACTIVE_MODE=false
fi

# Ensure valid execution
if [[ -z "$app_name[-1]" || "$app_name[-1]" == "null" ||
  -z "$app_url[-1]" || "$app_url[-1]" == "null" ||
  -z "$icon_ref[-1]" || "$icon_ref[-1]" == "null" ]]; then
  echo "You must set app name, app URL, and icon URL!"
  exit 1
fi

APP_NAME=$app_name[-1]
APP_URL=$app_url[-1]
ICON_REF=$icon_ref[-1]
CUSTOM_EXEC=$custom_exec[-1]
MIME_TYPES=$mime_types[-1]

# Refer to local icon or fetch remotely from URL
ICON_DIR="$HOME/.local/share/applications/icons"
# Ensure the icon directory exists (useful if it's the first run.)
[ ! -d $ICON_DIR ] && mkdir -p $ICON_DIR

if [[ $ICON_REF == https://* ]]; then
  ICON_PATH="$ICON_DIR/$APP_NAME.png"
  if curl -sL -o "$ICON_PATH" "$ICON_REF"; then
    ICON_PATH="$ICON_DIR/$APP_NAME.png"
  else
    echo "Error: Failed to download icon."
    exit 1
  fi
else
  # Check if the icon path is a file.
  if [ -f $ICON_REF ]; then
    ICON_PATH=$ICON_REF
  else
    ICON_PATH="$ICON_DIR/$ICON_REF"
  fi
fi

# Use custom exec if provided, otherwise default behavior
if [[ -n $CUSTOM_EXEC ]] && [[ ! $CUSTOM_EXEC == "null" ]]; then
  EXEC_COMMAND="$CUSTOM_EXEC"
else
  EXEC_COMMAND="${SCRIPTS:-$HOME/.local/scripts}/launch-webapp $APP_URL"
fi

# Create application .desktop file
DESKTOP_FILE="$HOME/.local/share/applications/$APP_NAME.desktop"

cat >"$DESKTOP_FILE" <<EOF
[Desktop Entry]
Version=1.0
Name=$APP_NAME
Comment=$APP_NAME
Exec=$EXEC_COMMAND
Terminal=false
Type=Application
Icon=$ICON_PATH
StartupNotify=true
EOF

# Add mime types if provided
if [[ -n $MIME_TYPES ]] && [[ ! $MIME_TYPES == "null" ]]; then
  echo "MimeType=$MIME_TYPES" >>"$DESKTOP_FILE"
fi

chmod +x "$DESKTOP_FILE"

if [[ $INTERACTIVE_MODE == true ]]; then
  echo -e "You can now find $APP_NAME using the app launcher (SUPER + SPACE)\n"
fi
