#!/bin/bash

# omarchy:group=transcode
# omarchy:name=
# omarchy:summary=Transcode pictures and videos for sharing
# omarchy:args=[--path path] [input] [format] [resolution]
# omarchy:examples=omarchy transcode|omarchy transcode --path ~/Downloads|omarchy transcode ~/Videos/demo.mov mp4 1080p|omarchy transcode ~/Pictures/wallpaper.heic jpg medium

set -euo pipefail

usage() {
  cat <<'EOF'
Usage:
  omarchy transcode [--path path] [input] [format] [resolution]

With no input, fuzzy-pick a picture or video from ~/Pictures and ~/Videos,
or only from --path when provided. Then pick the output format and resolution.

Options:
  --path path  Limit interactive fuzzy file selection to this path

Formats:
  Pictures: jpg, png
  Videos: mp4, gif

Resolutions:
  Pictures: high, medium, low
  Videos: 4k, 1080p, 720p
EOF
}

pick_file() {
  local search_path="$1"
  local paths=()

  if [[ -n $search_path ]]; then
    [[ -e $search_path ]] || { echo "Path not found: $search_path" >&2; return 1; }
    paths=("$search_path")
  else
    paths=("$HOME/Pictures" "$HOME/Videos")
  fi

  find "${paths[@]}" -type f \
    \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' -o -iname '*.gif' -o -iname '*.heic' -o -iname '*.avif' \
    -o -iname '*.mp4' -o -iname '*.mov' -o -iname '*.m4v' -o -iname '*.mkv' -o -iname '*.webm' -o -iname '*.avi' \) \
    -printf '%T@\t%p\n' 2>/dev/null | sort -rn | cut -f2- | fzf --layout=reverse-list --prompt="Transcode file> "
}

pick_option() {
  local prompt="$1"
  shift

  gum choose --header "$prompt" "$@"
}

media_type() {
  local mime
  mime=$(file -b --mime-type "$1")

  case "$mime" in
  image/*) echo picture ;;
  video/*) echo video ;;
  *)
    echo "Unsupported file type: $mime" >&2
    return 1
    ;;
  esac
}

output_path() {
  local input="$1"
  local format="$2"
  local resolution="$3"
  local dir base stem

  dir=$(dirname -- "$input")
  base=$(basename -- "$input")
  stem="${base%.*}"

  printf '%s/%s-%s.%s' "$dir" "$stem" "$resolution" "$format"
}

transcode_picture() {
  local input="$1" format="$2" resolution="$3" output="$4"
  local resize

  case "$resolution" in
  high) resize='3160x>' ;;
  medium) resize='2160x>' ;;
  low) resize='1080x>' ;;
  *)
    echo "Invalid picture resolution: $resolution" >&2
    return 1
    ;;
  esac

  case "$format" in
  jpg)
    magick "$input" -resize "$resize" -quality 85 -strip "$output"
    ;;
  png)
    magick "$input" -resize "$resize" -strip -define png:compression-filter=5 \
      -define png:compression-level=9 \
      -define png:compression-strategy=1 \
      -define png:exclude-chunk=all \
      "$output"
    ;;
  *)
    echo "Invalid picture format: $format" >&2
    return 1
    ;;
  esac
}

transcode_video() {
  local input="$1" format="$2" resolution="$3" output="$4"
  local scale

  case "$resolution" in
  4k) scale='scale=-2:2160' ;;
  1080p) scale='scale=-2:1080' ;;
  720p) scale='scale=-2:720' ;;
  *)
    echo "Invalid video resolution: $resolution" >&2
    return 1
    ;;
  esac

  case "$format" in
  mp4)
    if [[ $resolution == "4k" ]]; then
      ffmpeg -i "$input" -vf "$scale" -c:v libx265 -preset slow -crf 24 -c:a aac -b:a 192k "$output"
    else
      ffmpeg -i "$input" -vf "$scale" -c:v libx264 -preset fast -crf 23 -c:a copy "$output"
    fi
    ;;
  gif)
    ffmpeg -i "$input" -vf "fps=10,$scale:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" "$output"
    ;;
  *)
    echo "Invalid video format: $format" >&2
    return 1
    ;;
  esac
}

copy_to_clipboard() {
  local output="$1"
  local uri

  uri="file://$(realpath -- "$output")"
  printf '%s\n' "$uri" | wl-copy --type text/uri-list
}

main() {
  local input="" format="" resolution="" search_path=""
  local type output positional=()

  while (( $# > 0 )); do
    case "$1" in
    --path)
      shift
      [[ $# -gt 0 ]] || { echo "Missing value for --path" >&2; return 2; }
      search_path="$1"
      ;;
    --help | -h)
      usage
      return 0
      ;;
    --)
      shift
      positional+=("$@")
      break
      ;;
    --*)
      echo "Unknown option: $1" >&2
      usage >&2
      return 2
      ;;
    *)
      positional+=("$1")
      ;;
    esac
    shift
  done

  input="${positional[0]:-}"
  format="${positional[1]:-}"
  resolution="${positional[2]:-}"

  if [[ -z $input ]]; then
    input=$(pick_file "$search_path")
  fi

  [[ -n $input ]] || return 1
  [[ -f $input ]] || { echo "File not found: $input" >&2; return 1; }

  type=$(media_type "$input")

  if [[ -z $format ]]; then
    if [[ $type == "picture" ]]; then
      format=$(pick_option "Select format..." jpg png)
    else
      format=$(pick_option "Select format..." mp4 gif)
    fi
  fi

  if [[ -z $resolution ]]; then
    if [[ $type == "picture" ]]; then
      resolution=$(pick_option "Select resolution..." high medium low)
    else
      resolution=$(pick_option "Select resolution..." 4k 1080p 720p)
    fi
  fi

  output=$(output_path "$input" "$format" "$resolution")

  if [[ $type == "picture" ]]; then
    transcode_picture "$input" "$format" "$resolution" "$output"
  else
    transcode_video "$input" "$format" "$resolution" "$output"
    echo ""
  fi

  copy_to_clipboard "$output"
  echo "Your $type has been transcoded into $format as $resolution. It's on your clipboard."
  echo ""
  echo "It's also in $output"
}

main "$@"
