#!/bin/bash

set -euo pipefail

: ${HOME:="/Users/$(whoami)"}
: ${XDG_CONFIG_HOME:=$HOME/.config}
: ${XDG_DATA_HOME:=$HOME/.local/share}


_sed_i() {
  if [[ "$(uname)" == "Darwin" ]]; then
    sed -i '' "$@"
  else
    sed -i'' "$@"
  fi
}

is_auto_dark_mode() {
  if [[ "$OSTYPE" == "darwin"* ]]; then
    defaults read -g AppleInterfaceStyleSwitchesAutomatically >/dev/null 2>&1
  else
    true
  fi
}
is_ubuntu_desktop() {
  [[ "$(lsb_release -is)" == "Ubuntu" ]] \
  && dpkg -l | grep -q desktop
}
is_dark_mode() {
  if [[ "$OSTYPE" == "darwin"* ]]; then
    defaults read -g AppleInterfaceStyle >/dev/null 2>&1
  elif [[ -n "${SSH_CONNECTION:-}" ]]; then
    true
  elif is_ubuntu_desktop ; then
    [[ "$(gsettings get org.gnome.desktop.interface color-scheme 2>&1)" != *'light'* ]]
  else
    true
  fi
}
set_macos_dark_mode_to() {
  osascript -e 'tell application "System Events" to tell appearance preferences to set dark mode to '"$1"
}
set_dark_mode() {
  if [[ "$OSTYPE" == "darwin"* ]]; then
    set_macos_dark_mode_to "true"
  elif is_ubuntu_desktop ; then
    gsettings set org.gnome.desktop.interface color-scheme prefer-dark > /dev/null || true
  fi
}
unset_dark_mode() {
  if [[ "$OSTYPE" == "darwin"* ]]; then
    set_macos_dark_mode_to "false"
  elif is_ubuntu_desktop ; then
    gsettings set org.gnome.desktop.interface color-scheme prefer-light > /dev/null || true
  fi
}
get_mode() {
  local mode="${1:-}"
  if [[ -z "$mode" ]]; then
    if is_dark_mode ; then 
      mode="dark"
    else
      mode="light"
    fi
  fi
  if [[ "$mode" != "dark" && "$mode" != "light" ]]
  then
    >&2 echo "ERROR: unsupported mode '$mode'"
    exit 1
  fi
  if [[ "${mode}" == 'dark' ]] ; then
    echo "dark"
  else
    echo "light"
  fi
}
set_mode() {
  local mode="${1:-}"
  if [[ "$(get_mode "$mode")" == 'dark' ]]
  then
    set_dark_mode
  else
    unset_dark_mode
  fi
}



# List the available color config options
list_colors() {
  local ext="$1"
  local dir="$2"
  if [ ! -e "$dir" ] ; then
    echo "(none)"
    return
  fi
  find "${dir}/" -mindepth 1 -type f -print0 \
    | xargs -r -0 -n 1 basename \
    | sed 's/'"$ext"'$//' \
    | sort
}
# Select the first readable file from a list of filepaths
# specified as arguments.
first_file_in() {
  cd "$1"
  shift
  while [[ $# -ne 0 ]]
  do
    if [[ -r "$1" ]]
    then
      echo "$(pwd)/$1"
      return 0
    else
      shift
    fi
  done
  return 1
}
color_file() {
  local dir="$1"
  local ext="$2"
  local colors="$3"
  local mode="$4"
  if ! first_file_in "$dir" \
    "${colors}-${mode}${ext}" \
    "${colors}${mode}${ext}" \
    "${colors}${ext}" \
    "${mode}${ext}"
  then
    >&2 echo "ERROR: unable to load $ext colors for $colors $mode from $dir"
    return 1
  fi
}
# Create or replace colors in a given config file from another
# file specifying the color config content.
set_colors_in_config() {
  config_file="$1"
  colors_file="$2"
  line_comment_prefix="${3:-## }"
  if [[ -L "$config_file" ]]
  then
    config_file="$(readlink "$config_file")"
  fi
  mkdir -p "$(dirname "$config_file")"
  if [[ -r "$config_file" ]]
  then
    _sed_i '/GEN COLORS START/,/GEN COLORS END/d' "$config_file"
  fi
  cat >> "$config_file" <<EOF
$line_comment_prefix GEN COLORS START
$line_comment_prefix from: $colors_file
$(cat "$colors_file")
$line_comment_prefix GEN COLORS END
EOF
}

alacritty_ext='.toml'
alacritty_cfg="$XDG_DATA_HOME/alacritty/color${alacritty_ext}"
alacritty_colors_dir1="$XDG_CONFIG_HOME/alacritty/colors"
alacritty_colors_dir2="$HOME/src/alacritty/alacritty-theme/themes"
alacritty_colors() {
  {
    list_colors "${alacritty_ext}" "$alacritty_colors_dir1"
    list_colors "${alacritty_ext}" "$alacritty_colors_dir2"
  } | sort
}
alacritty_color_file() {
  color_file "${alacritty_colors_dir1}" "${alacritty_ext}" "$1" "$2" 2>/dev/null || \
  color_file "${alacritty_colors_dir2}" "${alacritty_ext}" "$1" "$2" 2>/dev/null || \
  color_file "${alacritty_colors_dir1}" "${alacritty_ext}" "$1" "$2"
}
alacritty_color_check_exists() {
  alacritty_color_file "$1" "$2" > /dev/null
}
alacritty_colors_set() {
  set_colors_in_config "${alacritty_cfg}" "$(alacritty_color_file "$1" "$2")"
  touch "$XDG_CONFIG_HOME/alacritty/alacritty${alacritty_ext}"
}

bat_ext='.sh'
bat_cfg="$XDG_DATA_HOME/bat/color.sh"
bat_colors_dir="$XDG_CONFIG_HOME/bat/colors"
bat_colors() {
  # list_colors "${bat_ext}" "$bat_colors_dir"
  bat --list-themes | cat
}
bat_color_file() {
  color_file "${bat_colors_dir}" "${bat_ext}" "$1" "$2"
}
bat_color_check_exists() {
  bat_color_file "$1" "$2" > /dev/null
}
bat_colors_set() {
  local mode="$2"

  # best for light: Coldark-Cold, Github, Monokai Extended Light, OneHalfLight, gruvbox-light
  # best for dark: 1337, Coldark-Dark, Monokai Extended, OneHalfDark, gruvbox-dark
  # works well with both: ansi
  local theme="1337"
  if [[ "$mode" == "light" ]]
  then
    theme="gruvbox-light"
  fi

  [[ -d "$(dirname "${bat_cfg}")" ]] || mkdir -p "$(dirname "${bat_cfg}")"
  echo "--theme='$theme'" > "${bat_cfg}"
}

tmux_ext='.conf'
tmux_cfg="$XDG_DATA_HOME/tmux/color.conf"
tmux_colors_dir="$XDG_CONFIG_HOME/tmux/colors"
tmux_colors() {
  list_colors "${tmux_ext}" "$tmux_colors_dir"
}
tmux_color_file() {
  color_file "${tmux_colors_dir}" "${tmux_ext}" "$1" "$2"
}
tmux_color_check_exists() {
  tmux_color_file "$1" "$2" > /dev/null
}
tmux_colors_set() {
  set_colors_in_config "${tmux_cfg}" "$(tmux_color_file "$1" "$2")"
  tmux source-file "${tmux_cfg}"
}

neovim_ext='.lua'
neovim_cfg="${XDG_DATA_HOME}/nvim/colors.lua"
neovim_colors_dir="$XDG_CONFIG_HOME/nvim/colors"
neovim_colors() {
  list_colors "${neovim_ext}" "$neovim_colors_dir"
}
neovim_color_file() {
  color_file "${neovim_colors_dir}" "${neovim_ext}" "$1" "$2"
}
neovim_color_check_exists() {
  neovim_color_file "$1" "$2" 2>/dev/null > /dev/null
}
neovim_colors_set() {
  colors="$1"
  mode="$2"
  if neovim_color_check_exists "${colors}" "${mode}"
  then
    set_colors_in_config "${neovim_cfg}" "$(neovim_color_file "$1" "$2")" '-- '
  else
    cat <<EOF > "${neovim_cfg}"
-- GEN COLORS START
local theme_mode = "$mode"
local theme_colors = "$colors"
$(cat "${neovim_colors_dir}/default.lua")
-- GEN COLORS END
EOF
  fi
}

ghostty_cfg="$XDG_DATA_HOME/ghostty/color"
ghostty_colors_dir="$XDG_CONFIG_HOME/ghostty/colors"
# Check if a custom Ghostty color file exists
ghostty_custom_color_file() {
  local colors="$1"
  local mode="$2"

  # Try to find custom color file (similar to other tools)
  if ! first_file_in "$ghostty_colors_dir" \
    "${colors}-${mode}" \
    "${colors}${mode}" \
    "${colors}"
  then
    return 1
  fi
}
# Map colorscheme names to Ghostty built-in theme names
ghostty_theme_name() {
  local colors="$1"
  local mode="$2"

  # Direct mappings for common colorschemes
  case "$colors" in
    molokai)
      # echo "Monokai Soda"
      # echo "Monokai Pro Spectrum"
      echo "Brogrammer"
      ;;
    gruvbox)
      if [[ "$mode" == "dark" ]]; then
        echo "Gruvbox Dark"
      else
        echo "Gruvbox Light"
      fi
      ;;
    papercolor)
      if [[ "$mode" == "dark" ]]; then
        echo "GitHub Dark Default"
      else
        echo "GitHub Light Default"
      fi
      ;;
    solarized)
      if [[ "$mode" == "dark" ]]; then
        echo "Solarized Dark Patched"
      else
        echo "Builtin Solarized Light"
      fi
      ;;
    nord)
      echo "Nord"
      ;;
    dracula)
      echo "Dracula"
      ;;
    *)
      # Fallback: try to find a matching theme name (case-insensitive)
      local search_term="$colors"
      ghostty +list-themes --plain 2>/dev/null | sed 's/ (resources)//' | grep -i "^${search_term}$" | head -n 1 || echo ""
      ;;
  esac
}
ghostty_colors() {
  {
    # List custom color files first
    if [[ -d "$ghostty_colors_dir" ]]; then
      find "$ghostty_colors_dir" -mindepth 1 -type f -print0 \
        | xargs -r -0 -n 1 basename \
        | sort
    fi
    # Then list built-in themes
    ghostty +list-themes --plain 2>/dev/null | sed 's/ (resources)//'
  } | sort -u || echo "(ghostty not found)"
}
ghostty_color_check_exists() {
  local colors="$1"
  local mode="$2"

  # # First check for custom color file
  # if ghostty_custom_color_file "$colors" "$mode" >/dev/null 2>&1; then
  #   return 0
  # fi

  # Then check for built-in theme
  local theme_name
  theme_name="$(ghostty_theme_name "$colors" "$mode")"
  if [[ -n "$theme_name" ]]; then
    return 0
  else
    return 1
  fi
}
ghostty_colors_set() {
  local colors="$1"
  local mode="$2"
  local custom_file
  local theme_name

  mkdir -p "$(dirname "$ghostty_cfg")"

  # First priority: use custom color file if it exists
  if custom_file="$(ghostty_custom_color_file "$colors" "$mode" 2>/dev/null)"; then
    cat > "$ghostty_cfg" <<EOF
# Generated by theme script
# Colorscheme: $colors ($mode)
# Using custom color file: $custom_file
$(cat "$custom_file")
EOF
  else
    # Second priority: use built-in theme
    theme_name="$(ghostty_theme_name "$colors" "$mode")"

    if [[ -z "$theme_name" ]]; then
      >&2 echo "WARNING: No Ghostty theme found for '$colors' in $mode mode, skipping Ghostty theme update"
      return 0
    fi

    cat > "$ghostty_cfg" <<EOF
# Generated by theme script
# Colorscheme: $colors ($mode)
# Using built-in theme: $theme_name
theme = $theme_name
EOF
  fi

  # Trigger Ghostty reload
  local script_dir
  script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  "$script_dir/ghostty-reload"
}



# default colors file saves the local colors preference for each mode
default_colors_file_dark="${XDG_DATA_HOME}/dark-colors"
default_colors_file_light="${XDG_DATA_HOME}/light-colors"
get_default_colors_file() {
  local mode="${1-:}"
  if [[ "$(get_mode "$mode")" == "dark" ]] ; then
    echo "${default_colors_file_dark}"
  else
    echo "${default_colors_file_light}"
  fi
}
get_colors() {
  local mode="${1:-}"
  local file
  file="$(get_default_colors_file "$mode" )"
  if [[ -r "$file" ]]
  then
    cat "$file"
  else
    is_dark_mode && echo "molokai" || echo "papercolor"
  fi
}
common_colors() {
  local col com aux types
  col="$(mktemp)"
  com="$(mktemp)"
  aux="$(mktemp)"
  types=(
    bat
    tmux
    neovim
    alacritty
    ghostty
  )
  for typ in "${types[@]}"; do
    echo "[[ $typ ]]"
    "${typ}_colors" | sort | tee "${col}"
    if [[ "$(wc -l < "${com}")" -gt 0 ]]; then
      comm -12 "${com}" "${col}" > "${aux}"
      cp "${aux}" "${com}"
    else
      cp "${col}" "${com}"
    fi
    echo ""
  done
  echo "[[ common ]]"
  cat "${com}"
  rm "${com}" "${aux}"
}
color_check_exists() {
  local colors="$1"
  local mode="$2"
  if ! tmux_color_check_exists "$colors" "$mode"; then
    >&2 echo "ERROR: tmux colors '$colors' not found for mode '$mode'"
    return 1
  fi
  if ! alacritty_color_check_exists "$colors" "$mode"; then
    >&2 echo "ERROR: alacritty colors '$colors' not found for mode '$mode'"
    return 1
  fi
  # neovim and bat have fallback mechanisms, so don't require strict checking
  return 0
}
set_colors() {
  local mode="$1"
  local colors="$2"
  if [[ -z "$mode" ]]; then
    mode="$(get_mode)"
  fi
  if [[ -z "$colors" ]]; then
    colors="$(get_colors "$mode")"
  fi
  color_check_exists "$colors" "$mode"

  bat_colors_set "$colors" "$mode"
  tmux_colors_set "$colors" "$mode"
  neovim_colors_set "$colors" "$mode"
  alacritty_colors_set "$colors" "$mode"
  ghostty_colors_set "$colors" "$mode"

  local colors_file
  colors_file="$(get_default_colors_file "$mode")"
  mkdir -p "$(dirname "$colors_file")"
  echo "$colors" > "$colors_file" 2>/dev/null || true
}

set_theme() {
  local mode=$1
  local colors=$2

  set_mode "$mode"
  set_colors "$mode" "$colors"

  echo "Set theme to $(get_mode "$mode") $(get_colors "$mode")"
}

print_help() {
    local s_name
    s_name="$(basename $0)"
    cat <<EOF
Help

Current set theme:

  $s_name

Current mode

  $s_name --mode

Current colorscheme

  $s_name --colors

Set theme

  $s_name --set [light|dark] [colorscheme]

List available colorschemes

  $s_name --list
  $s_name --list-bat
  $s_name --list-tmux
  $s_name --list-neovim
  $s_name --list-alacritty
  $s_name --list-ghostty
EOF
}

if test $# -eq 0
then
  echo "$(get_mode) $(get_colors)"
  exit 0
fi

while test $# -gt 0
do
  case $1 in
    --mode)
      get_mode; exit 0; ;;
    --colors)
      get_colors; exit 0; ;;
    --set)
      set_theme "${2:-}" "${3:-}"; exit 0; ;;
    --list-alacritty)
      alacritty_colors; exit 0; ;;
    --list-tmux)
      tmux_colors; exit 0; ;;
    --list-neovim)
      neovim_colors; exit 0; ;;
    --list-bat)
      bat_colors; exit 0; ;;
    --list-ghostty)
      ghostty_colors; exit 0; ;;
    --list)
      common_colors; exit 0; ;;
    --help|-h)
      print_help; exit 0; ;;
    *)
      print_help; exit 1; ;;
  esac
  shift
done

>&2 echo "ERROR: Unexpected state!"
exit 1

