#!/usr/bin/env bash

# ============================================================
# FTP upload script
# - Never creates a missing series folder.
# - Creates only resolution/subtitle folders inside an existing series folder.
# - Continues after unmatched files or failed uploads.
# - Prints a final report and writes log files.
# ============================================================

# --- Server Configuration ---
declare -A FTP_SERVERS=(
  ["2026/Winter"]="5.239.244.217|csdl1|m7TkFTYKKwewA67P|/anime/2026/Winter"
  ["2026/Spring"]="5.239.244.217|csdl1|m7TkFTYKKwewA67P|/anime/2026/Spring"
  ["Ronak 2026/Summer"]="188.75.78.114|rdl1hollowofthealley|CwZDUCzUenyKd75c9Bgy|/domains/rdl1.hollowofthealley.space/public_html/anime/2026/Summer"
  ["Ronak 2026/ONA"]="188.75.78.114|rdl1hollowofthealley|CwZDUCzUenyKd75c9Bgy|/domains/rdl1.hollowofthealley.space/public_html/anime/2026/ONA"
  ["Ronak Anime"]="188.75.78.114|rdl1hollowofthealley|CwZDUCzUenyKd75c9Bgy|/domains/rdl1.hollowofthealley.space/public_html/anime"
)

PRESET_PROXY_URL="http://2.144.15.111:2525"
LOG_SKIPPED="upload_skipped.log"
LOG_FAILED="upload_failed.log"
LOG_SUCCESS="upload_success.log"

: > "$LOG_SKIPPED"
: > "$LOG_FAILED"
: > "$LOG_SUCCESS"

command -v lftp >/dev/null 2>&1 || {
  echo "ERROR: lftp is not installed."
  exit 1
}

ask_yes_no() {
  local prompt="$1" answer
  while true; do
    read -r -p "$prompt [y/n]: " answer
    case "$answer" in
      [Yy]*) return 0 ;;
      [Nn]*) return 1 ;;
      *) echo "Please answer y or n." ;;
    esac
  done
}

trim() {
  sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' <<< "$1"
}

normalize() {
  local value="${1//$'\r'/}"
  LC_ALL=C tr '[:upper:]' '[:lower:]' <<< "$value" \
    | sed -E 's/[–—−]/-/g' \
    | tr -cd '[:alnum:]'
}

join_path() {
  printf '%s/%s' "${1%/}" "${2#/}"
}

# Quote one argument for the lftp command parser.
# Commands are sent through stdin, so double quotes work normally here.
lftp_quote() {
  local value="$1"
  value=${value//\\/\\\\}
  value=${value//\"/\\\"}
  value=${value//$'\n'/ }
  value=${value//$'\r'/ }
  printf '"%s"' "$value"
}

extract_series_name() {
  local file="$1"
  local base="${file##*/}"
  local name="${base%.*}"
  local current before after result

  if [[ "$name" != *" - "* ]]; then
    printf '%s\n' "$name"
    return
  fi

  result="${name%% - *}"
  current="$name"

  while [[ "$current" == *" - "* ]]; do
    before="${current% - *}"
    after="${current##* - }"

    if [[ "$after" =~ ^[[:space:]]*([0-9]+|\[) ]]; then
      result="$before"
      break
    fi

    current="$before"
  done

  printf '%s\n' "$result"
}

log_skipped() {
  printf '%s | %s | Series: %s | %s\n' \
    "$(date +'%Y-%m-%d %H:%M:%S')" "$1" "$2" "$3" >> "$LOG_SKIPPED"
}

log_failed() {
  printf '%s | %s | Destination: %s | %s\n' \
    "$(date +'%Y-%m-%d %H:%M:%S')" "$1" "$2" "$3" >> "$LOG_FAILED"
}

log_success() {
  printf '%s | %s | Destination: %s\n' \
    "$(date +'%Y-%m-%d %H:%M:%S')" "$1" "$2" >> "$LOG_SUCCESS"
}

# Run lftp commands supplied on stdin.
# Usage: printf 'command\n' | run_lftp
run_lftp() {
  local preamble

  preamble=$(cat <<PREAMBLE
set ftp:ssl-allow no
set ssl:verify-certificate no
set ftp:charset UTF-8
set net:timeout 30
set net:max-retries 3
set net:reconnect-interval-base 5
set net:reconnect-interval-multiplier 1
PREAMBLE
)

  if [[ "$USE_PROXY" == true ]]; then
    preamble+=$'\n'"set http:proxy $PRESET_PROXY_URL"
    preamble+=$'\n'"set ftp:proxy $PRESET_PROXY_URL"
  fi

  {
    printf '%s\n' "$preamble"
    cat
    printf '%s\n' "bye"
  } | lftp -u "$FTP_USER,$FTP_PASS" "ftp://$FTP_HOST"
}

# ============================================================
# Server selection
# ============================================================

echo "Available FTP servers:"
select server_name in "${!FTP_SERVERS[@]}"; do
  if [[ -n "${server_name:-}" ]]; then
    IFS='|' read -r FTP_HOST FTP_USER FTP_PASS REMOTE_BASE \
      <<< "${FTP_SERVERS[$server_name]}"
    break
  fi
  echo "Invalid selection. Try again."
done

REMOTE_BASE="${REMOTE_BASE%/}"

echo
echo "Selected server: $server_name"
echo "FTP host:        $FTP_HOST"
echo "Remote path:     $REMOTE_BASE"

USE_PROXY=false
echo
if ask_yes_no "Do you want to use the proxy?"; then
  USE_PROXY=true
  echo "Proxy enabled: $PRESET_PROXY_URL"
else
  echo "Proxy disabled."
fi

# ============================================================
# Validate login and path
# ============================================================

echo
echo "Checking FTP login and remote path..."

check_output="$({
  printf 'set cmd:fail-exit yes\n'
  printf 'cd %s\n' "$(lftp_quote "$REMOTE_BASE")"
  printf 'pwd\n'
} | run_lftp 2>&1)"
check_status=$?

if [[ $check_status -ne 0 ]]; then
  echo "ERROR: FTP login or remote path check failed."
  echo "Remote path: $REMOTE_BASE"
  echo "lftp output:"
  echo "------------------------------------------------------------"
  printf '%s\n' "$check_output"
  exit 1
fi

echo "FTP login and remote path are valid."

if ! ask_yes_no "Continue with listing remote series folders?"; then
  echo "Aborting."
  exit 0
fi

# ============================================================
# List existing series folders
# ============================================================

echo
echo "Fetching existing folders inside $REMOTE_BASE ..."

remote_output="$({
  printf 'set cmd:fail-exit yes\n'
  printf 'cd %s\n' "$(lftp_quote "$REMOTE_BASE")"
  printf 'cls -la\n'
} | run_lftp 2>&1)"
remote_status=$?

if [[ $remote_status -ne 0 ]]; then
  echo "ERROR: Failed to list the remote directory."
  printf '%s\n' "$remote_output"
  exit 1
fi

# Parse long FTP listing. Everything after the date/time columns is the name.
mapfile -t REMOTE_FOLDERS < <(
  printf '%s\n' "$remote_output" \
    | sed -E $'s/\r//g; s/\x1B\\[[0-9;]*[A-Za-z]//g' \
    | awk '
      /^d/ {
        line=$0
        if (match(line, /[A-Z][a-z][a-z][[:space:]]+[0-9]{1,2}[[:space:]]+([0-9]{2}:[0-9]{2}|[0-9]{4})[[:space:]]+/)) {
          name=substr(line, RSTART+RLENGTH)
          sub(/\/$/, "", name)
          if (name != "." && name != ".." && name != "") print name
        }
      }
    '
)

if [[ ${#REMOTE_FOLDERS[@]} -eq 0 ]]; then
  echo "ERROR: The path exists, but no series folders were found."
  echo "Raw lftp output:"
  echo "------------------------------------------------------------"
  printf '%s\n' "$remote_output"
  exit 1
fi

echo "Found ${#REMOTE_FOLDERS[@]} existing series folders:"
for folder in "${REMOTE_FOLDERS[@]}"; do
  printf ' - %s\n' "$folder"
done

if ! ask_yes_no "Continue with file matching and upload?"; then
  echo "Aborting."
  exit 0
fi

# ============================================================
# Match files
# ============================================================

declare -A FILE_SERIES_PATH
declare -A FILE_TARGET_PATH

a=0
TOTAL_FILES=0
MATCHED_FILES=0
SKIPPED_FILES=0
SUCCESSFUL_UPLOADS=0
FAILED_UPLOADS=0

shopt -s nullglob nocaseglob

echo
echo "Analyzing local files..."

for file in *.mkv *.ass *.srt; do
  [[ -f "$file" ]] || continue
  TOTAL_FILES=$((TOTAL_FILES + 1))

  series_name="$(trim "$(extract_series_name "$file")")"
  series_key="$(normalize "$series_name")"
  matched_folder=""

  for folder in "${REMOTE_FOLDERS[@]}"; do
    folder_key="$(normalize "$folder")"
    if [[ -n "$folder_key" && "$folder_key" == "$series_key" ]]; then
      matched_folder="$folder"
      break
    fi
  done

  if [[ -z "$matched_folder" ]]; then
    for folder in "${REMOTE_FOLDERS[@]}"; do
      folder_key="$(normalize "$folder")"
      [[ -n "$folder_key" && -n "$series_key" ]] || continue
      if [[ "$folder_key" == *"$series_key"* || "$series_key" == *"$folder_key"* ]]; then
        matched_folder="$folder"
        break
      fi
    done
  fi

  if [[ -z "$matched_folder" ]]; then
    echo "SKIPPED: $file"
    echo "Reason: No existing remote series folder for '$series_name'."
    log_skipped "$file" "$series_name" "No existing remote series folder"
    SKIPPED_FILES=$((SKIPPED_FILES + 1))
    continue
  fi

  series_path="$(join_path "$REMOTE_BASE" "$matched_folder")"
  target_path="$series_path"
  lowercase_file="${file,,}"

  case "$lowercase_file" in
    *.ass|*.srt)
      target_path="$(join_path "$series_path" "sub")"
      ;;
    *.mkv)
      if [[ "$lowercase_file" == *1080p* ]]; then
        if [[ "$lowercase_file" == *x265* || "$lowercase_file" == *h265* || "$lowercase_file" == *hevc* ]]; then
          target_path="$(join_path "$series_path" "1080 x265")"
        else
          target_path="$(join_path "$series_path" "1080")"
        fi
      elif [[ "$lowercase_file" == *720p* ]]; then
        if [[ "$lowercase_file" == *x265* || "$lowercase_file" == *h265* || "$lowercase_file" == *hevc* ]]; then
          target_path="$(join_path "$series_path" "720 x265")"
        else
          target_path="$(join_path "$series_path" "720")"
        fi
      elif [[ "$lowercase_file" == *480p* ]]; then
        target_path="$(join_path "$series_path" "480")"
      fi
      ;;
  esac

  FILE_SERIES_PATH["$file"]="$series_path"
  FILE_TARGET_PATH["$file"]="$target_path"
  MATCHED_FILES=$((MATCHED_FILES + 1))

  echo "MATCHED: $file"
  echo "Destination: $target_path"
done

# ============================================================
# Upload
# ============================================================

if [[ ${#FILE_TARGET_PATH[@]} -eq 0 ]]; then
  echo "No files matched existing remote series folders."
else
  echo
  echo "Starting upload of ${#FILE_TARGET_PATH[@]} files..."

  for file in "${!FILE_TARGET_PATH[@]}"; do
    series_path="${FILE_SERIES_PATH[$file]}"
    target_path="${FILE_TARGET_PATH[$file]}"

    # Create only the final resolution/subtitle folder, after entering
    # the already-existing series folder. Never use mkdir -p.
    if [[ "$target_path" != "$series_path" ]]; then
      subfolder="${target_path##*/}"

      create_output="$({
        printf 'set cmd:fail-exit yes\n'
        printf 'cd %s\n' "$(lftp_quote "$series_path")"
        # -f means no error if it already exists. It does not create parents.
        printf 'mkdir -f %s\n' "$(lftp_quote "$subfolder")"
      } | run_lftp 2>&1)"
      create_status=$?

      if [[ $create_status -ne 0 ]]; then
        echo "FAILED: $file"
        echo "Reason: Could not access the existing series folder or create its subfolder."
        printf '%s\n' "$create_output"
        log_failed "$file" "$target_path" "Could not access series folder or create subfolder"
        FAILED_UPLOADS=$((FAILED_UPLOADS + 1))
        continue
      fi
    fi

    echo "Uploading: $file"
    echo "Destination: $target_path"

    upload_output="$({
      printf 'set cmd:fail-exit yes\n'
      printf 'cd %s\n' "$(lftp_quote "$target_path")"
      printf 'put %s\n' "$(lftp_quote "$file")"
    } | run_lftp 2>&1)"
    upload_status=$?

    if [[ $upload_status -eq 0 ]]; then
      echo "SUCCESS: $file"
      log_success "$file" "$target_path"
      SUCCESSFUL_UPLOADS=$((SUCCESSFUL_UPLOADS + 1))
    else
      echo "FAILED: $file"
      echo "lftp output:"
      echo "------------------------------------------------------------"
      printf '%s\n' "$upload_output"
      log_failed "$file" "$target_path" "Upload failed with exit code $upload_status"
      FAILED_UPLOADS=$((FAILED_UPLOADS + 1))
    fi
  done
fi

# ============================================================
# Final report
# ============================================================

echo
echo "============================================================"
echo "Final report"
echo "============================================================"
echo "Files found:                 $TOTAL_FILES"
echo "Files matched:               $MATCHED_FILES"
echo "Files without series folder: $SKIPPED_FILES"
echo "Successful uploads:          $SUCCESSFUL_UPLOADS"
echo "Failed uploads:              $FAILED_UPLOADS"
echo "============================================================"
echo

if [[ -s "$LOG_SKIPPED" ]]; then
  echo "Files without an existing series folder:"
  echo "------------------------------------------------------------"
  cat "$LOG_SKIPPED"
  echo
fi

if [[ -s "$LOG_FAILED" ]]; then
  echo "Failed uploads:"
  echo "------------------------------------------------------------"
  cat "$LOG_FAILED"
  echo
fi

echo "Successful uploads log: $LOG_SUCCESS"
echo "Skipped files log:      $LOG_SKIPPED"
echo "Failed uploads log:     $LOG_FAILED"
echo "All done."