#!/usr/bin/env bash

set -e
set -o nounset
set -o pipefail

SCRIPTS=${SCRIPTS:-$HOME/.local/scripts}
THIS_FILE=${BASH_SOURCE[0]}
LOG_LABEL=$(basename "$THIS_FILE")
LOG_FILE=${LOG_FILE:-"$LOG_LABEL.log"}
THIS=${THIS:-$LOG_LABEL}
FZF_DEFAULT_OPTS=${FZF_DEFAULT_OPTS:-""}

usage() {
  cat <<EOF

Shows a picker of actions that can be performed on a window. The chosen action will
be performed on the window.

USAGE:

  $ $THIS <flags> <address>

FLAGS:
  -a | --active:      Uses the active window to perform the selected action.
  --show-back:        Shows a back option in the list of choices, useful when called from another script.
  -h | --help:        Show this help page.

EOF
}

address=""
move_silent_flag="0"
show_back_choice="0"

# Logging utility function, use in place of echo.
log() {
  logging log --source "$THIS_FILE" "$@"
}

action_footer() {
  cat <<'EOF'
   ___      __  _         
  / _ |____/ /_(_)__  ___ 
 / __ / __/ __/ / _ \/ _ \
/_/ |_\__/\__/_/\___/_//_/
                          
EOF
}

# Prevent hyprctl dispatch calls from printing to the console.
hypr_dispatch() {
  hyprctl dispatch "$@" >/dev/null 2>&1
  return $?
}

parse_workspace_id() {
  local workspace_name=""
  read -r workspace_name

  log "Parsing selected workspace name: $workspace_name"

  if [[ -z $workspace_name ]]; then
    log --error "No workspace set to move window to." && exit 1
  fi

  if [[ $workspace_name =~ ^special ]]; then
    log "Special workspace, returning name."
    echo $workspace_name
  else
    local id="$(hyprctl workspaces -j | jq -r ".[] | select(.name | contains(\"$workspace_name\")) | .id")"
    log "Selected workspace id: $id"
    echo "$id"
  fi
}

move_to_workspace() {

  log "Moving window: '$address'"
  log "Prompting for workspace to move to..."

  local action="movetoworkspace"
  if [[ $move_silent_flag == "1" ]]; then
    action="movetoworkspacesilent"
  fi

  $SCRIPTS/hypr/workspacectl picker --return-name-if-special --header="Select a workspace to move window to:" |
    parse_workspace_id |
    xargs -I{} hyprctl dispatch "$action" "{},address:$address" >/dev/null 2>&1

  return $?
}

toggle_floating() {
  log "Toggling floating..."
  local did_handle="0"
  local should_prompt_for_size="1"
  local is_floating=$(hyprctl clients -j | jq ".[] | select(.address == \"$address\") | .floating")

  if [[ $is_floating == "false" ]]; then
    gum confirm "Would you like to set the size of the float?"
    should_prompt_for_size=$?
  fi

  if [[ $should_prompt_for_size == "0" ]]; then
    log "Prompting for size..."
    placeholder="Example: 80% or 1000"
    width=$(gum input --placeholder="$placeholder" --header="Window Width:")
    height=$(gum input --placeholder="$placeholder" --header="Window Height:")
    if [[ -n $width ]] && [[ -n $height ]]; then
      "$SCRIPTS/hypr/utils/windows/window-toggle-floating" "$address" --width "$width" --height "$height"
      did_handle="1"
    else
      log --warning "Did not get both width: '$width' and height: '$height', not setting window size."
    fi
  fi

  if [[ $did_handle == "0" ]]; then
    "$SCRIPTS/hypr/utils/windows/window-toggle-floating" "$address"
  fi

}

make_selection() {
  log "Prompting for window action..."
  local choices=(
    "$address:Focus the selected window.:Focus window"
    "$address:Close the selected window.:Close window"
    "$address:Close the selected window and go back to the window list.:Close window and back"
    "$address:Move the selected window to another workspace, focusing the window.\n\nA workspace picker will be presented to choose which workspace to move to.:Move to workspace"
    "$address:Move the selected window to another workspace, without focusing the window.\n\nA workspace picker will be presented to choose which workspace to move to.:Move to workspace - silent"
    "$address:Toggles the selected windows floating property.\n\nIf the window is not floating then you will be prompted if you want to set the size or not.:Toggle floating"
    "$address:Copy the window address to the system clipboard:Copy to clipboard"
  )
  if [[ $show_back_choice == "1" ]]; then
    log "Adding show back choice option."
    choices+=("$address:Move back to window picker and reload windows.:Back")
  fi
  choices+=("$address:Quit and close the application:Quit")
  local choice=$(
    printf "%s\n" "${choices[@]}" |
      fzf --style=full --footer="$(action_footer)" \
        --delimiter=':' --with-nth=3 \
        --header="What should we do with the selected window?" \
        --preview-label="[ Description ]" \
        --preview='echo -e {2} | fmt -w ${FZF_PREVIEW_COLUMNS:-40}; echo -e "\n\n\e[35mSelected Window:\e[0m"; "$SCRIPTS/hypr/utils/fzf/preview-stats" window {1} "{title, workspace, address, floating}";'
  )
  # Exit if non-zero code returned from making selection.
  [[ $? -gt 0 ]] && log --error "Unexpected fzf status: $?" && exit $?
  # Set choice to just the action portion.
  choice="${choice##*:}"
  echo "$choice"
}

# Set appropriate flags based on the choice and perform the action on the window address.
handle_selection() {
  local resp="done"
  local choice=""
  read -r choice
  log "Action Choice: $choice"
  if [[ $choice == "Quit" ]]; then
    log "Quitting..."
  elif [[ $choice == "Close window" ]]; then
    log "Closing window..."
    "$SCRIPTS/hypr/utils/windows/close-windows" "$address"
  elif [[ $choice == "Close window and back" ]]; then
    log "Closing window and setting should go back flag."
    "$SCRIPTS/hypr/utils/windows/close-windows" "$address"
    resp="back:close"
  elif [[ $choice == "Copy to clipboard" ]]; then
    log "Copied window address to the clipboard."
    echo $address | wl-copy
  elif [[ $choice == "Focus window" ]]; then
    "$SCRIPTS/hypr/utils/windows/focus-window" $address
  elif [[ $choice == "Move to workspace" ]]; then
    move_to_workspace
  elif [[ $choice == "Move to workspace - silent" ]]; then
    move_silent_flag="1"
    move_to_workspace
    resp="back"
  elif [[ $choice == "Toggle floating" ]]; then
    toggle_floating
  elif [[ $choice == "Back" ]]; then
    resp="back"
  fi

  echo "$resp"

}

################################################################################
# MAIN
################################################################################

# Setup logging file and label.
source "$SCRIPTS/hypr/logging"
setup-logging "$LOG_FILE" "$LOG_LABEL"

while [[ $# -gt 0 ]]; do
  if [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then
    usage && exit 0
  elif [[ $1 == "-a" ]] || [[ $1 == "--active" ]]; then

    class=$(hyprctl activewindow -j | jq -r '.class')
    if [[ $class == "com.ghostty.windowctl" ]]; then
      # Select the previously focused window if we were launched in a new terminal window.
      address=$(hyprctl clients -j | jq -r '.[] | select(.focusHistoryID == 1) | .address')
    else
      # Select the active address if not.
      address=$(hyprctl activewindow -j | jq -r '.address')
    fi

  elif [[ $1 == "--show-back" ]]; then
    show_back_choice="1"
  else
    address=$1
  fi
  shift
done

# If an address not supplied then read from stdin, which allows us to pipe the address into
# this command.
if [[ -z $address ]]; then
  read -p "Window address: " address
fi

# Load colors if they haven't been loaded already.
[[ -z ${FZF_DEFAULT_OPTS} ]] &&
  [[ -f $SCRIPTS/catppuccin-colors ]] &&
  source $SCRIPTS/catppuccin-colors

if [[ -z $address ]]; then
  log --error "Address not set."
  exit 1
fi

res=$(make_selection | handle_selection)
log "Action result: $res"
# Returns "done | back | back:close" for parent script to know how to handle.
echo "$res"
