#! /usr/bin/env nix-shell
#! nix-shell -i bash -p bash exiftool

# Directory to start the search
base_dir=~/Pictures/Photos/Camera
log_file="metadata_changes.log"
temp_file="metadata_changes_temp.log"

# Function to extract date and time from filename
extract_datetime_from_filename() {
  filename=$(basename "$1")
  datetime=""

  # Patterns to match filenames with date and time
  if [[ "$filename" =~ ([0-9]{4})-([0-9]{2})-([0-9]{2})_([0-9]{2})_([0-9]{2})_([0-9]{2}) ]]; then
    datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} ${BASH_REMATCH[4]}:${BASH_REMATCH[5]}:${BASH_REMATCH[6]}"
  elif [[ "$filename" =~ ([0-9]{4})([0-9]{2})([0-9]{2})_([0-9]{2})([0-9]{2})([0-9]{2}) ]]; then
    datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} ${BASH_REMATCH[4]}:${BASH_REMATCH[5]}:${BASH_REMATCH[6]}"
  elif [[ "$filename" =~ ([0-9]{8})_([0-9]{6}) ]]; then
    datetime="${BASH_REMATCH[1]:0:4}:${BASH_REMATCH[1]:4:2}:${BASH_REMATCH[1]:6:2} ${BASH_REMATCH[2]:0:2}:${BASH_REMATCH[2]:2:2}:${BASH_REMATCH[2]:4:2}"
  elif [[ "$filename" =~ ([0-9]{8})([0-9]{6}) ]]; then
    datetime="${BASH_REMATCH[1]:0:4}:${BASH_REMATCH[1]:4:2}:${BASH_REMATCH[1]:6:2} ${BASH_REMATCH[2]:0:2}:${BASH_REMATCH[2]:2:2}:${BASH_REMATCH[2]:4:2}"
  elif [[ "$filename" =~ ([0-9]{8}) ]]; then
    datetime="${BASH_REMATCH[1]:0:4}:${BASH_REMATCH[1]:4:2}:${BASH_REMATCH[1]:6:2} 00:00:00"
  elif [[ "$filename" =~ ([0-9]{4})-([0-9]{2})-([0-9]{2})\ ([0-9]{2})_([0-9]{2})_([0-9]{2}) ]]; then
    datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} ${BASH_REMATCH[4]}:${BASH_REMATCH[5]}:${BASH_REMATCH[6]}"
  elif [[ "$filename" =~ ([0-9]{4})-([0-9]{2})-([0-9]{2}) ]]; then
    datetime="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}:${BASH_REMATCH[3]} 00:00:00"
  fi

  # Validate extracted date
  if echo "$datetime" | grep -qE '^([0-9]{4}):([0-9]{2}):([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$'; then
    year=$(echo "$datetime" | cut -d':' -f1)
    month=$(echo "$datetime" | cut -d':' -f2)
    day=$(echo "$datetime" | cut -d':' -f3 | cut -d' ' -f1)
    hour=$(echo "$datetime" | cut -d' ' -f2 | cut -d':' -f1)
    minute=$(echo "$datetime" | cut -d':' -f2 | cut -d':' -f2)
    second=$(echo "$datetime" | cut -d':' -f2 | cut -d':' -f3)

    # Remove leading zeros for validation
    year=$((10#$year))
    month=$((10#$month))
    day=$((10#$day))
    hour=$((10#$hour))
    minute=$((10#$minute))
    second=$((10#$second))

    if ((year < 2009 || year > 2024)) || ((month < 1 || month > 12)) || ((day < 1 || day > 31)) || ((hour > 23)) || ((minute > 59)) || ((second > 59)); then
      datetime=""
    fi
  else
    datetime=""
  fi

  echo "$datetime"
}

# Function to log changes
log_change() {
  photo="$1"
  old_date="$2"
  new_date="$3"
  action="$4"
  touch "$temp_file"
  {
    echo "File: $photo"
    echo "  Old Date: $old_date"
    echo "  New Date: $new_date"
    if [ -n "$action" ]; then
      echo "  Suggested action: $action"
    fi
    echo ""
  } >>"$temp_file"
}

# Function to handle errors and convert images to JPEG using ImageMagick
handle_conversion_error() {
  photo="$1"
  file_type=$(file --mime-type -b "$photo")

  if [[ $file_type == image/* ]]; then
    echo "Converting $photo to jpg using ImageMagick."
    mogrify -format jpg "$photo"
  else
    echo "File is a video or unsupported type: $photo. Skipping conversion."
  fi
}

# Loop through each year directory
for year_dir in "$base_dir"/*/; do
  year=$(basename "$year_dir")

  # Exclude VFS directory
  if [ "$year" == "VFS" ]; then
    continue
  fi

  # Loop through each month directory
  for month_dir in "$year_dir"*/; do
    month=$(basename "$month_dir")

    # Loop through each photo in the month directory
    for photo in "$month_dir"*; do
      if [ -f "$photo" ]; then
        # Extract the date from the photo metadata
        photo_date=$(exiftool -DateTimeOriginal -d "%Y:%m:%d %H:%M:%S" "$photo" | awk -F': ' '{print $2}')

        if [ -z "$photo_date" ]; then
          # Scenario 2: No date metadata or invalid date
          filename_datetime=$(extract_datetime_from_filename "$photo")

          if [ -n "$filename_datetime" ]; then
            new_date="$filename_datetime"
            log_change "$photo" "No date metadata" "$new_date"
            echo "Found: $photo"
            echo "  Extracted date from filename: $new_date"
          else
            new_date="$year:$month:01 00:00:00"
            log_change "$photo" "No date metadata" "$new_date"
            echo "Found: $photo"
            echo "  Defaulting to directory date: $new_date"
          fi
        else
          photo_year=$(echo "$photo_date" | cut -d':' -f1)
          photo_month=$(echo "$photo_date" | cut -d':' -f2)

          if [ "$photo_year" != "$year" ] || [ "$photo_month" != "$month" ]; then
            # Scenario 1: Date mismatch
            filename_datetime=$(extract_datetime_from_filename "$photo")

            if [ -n "$filename_datetime" ]; then
              filename_year=$(echo "$filename_datetime" | cut -d':' -f1)
              filename_month=$(echo "$filename_datetime" | cut -d':' -f2)
              if [ "$photo_year" == "$filename_year" ] && [ "$photo_month" == "$filename_month" ]; then
                echo "Mismatch found: $photo"
                echo "  Directory date: $year/$month"
                echo "  Photo date: $photo_date"
                echo "  Filename date matches photo date, file is in the wrong directory."
                action="Move to $filename_year/$filename_month"
                log_change "$photo" "$photo_date" "$filename_datetime" "$action"
              else
                new_date="$filename_datetime"
                log_change "$photo" "$photo_date" "$new_date"
                echo "Mismatch found: $photo"
                echo "  Directory date: $year/$month"
                echo "  Photo date: $photo_date"
                echo "  Filename date: $filename_datetime"
                echo "  Suggested action: Update photo metadata to match filename date."
              fi
            else
              new_date="$year:$month:01 00:00:00"
              log_change "$photo" "$photo_date" "$new_date"
              echo "Mismatch found: $photo"
              echo "  Directory date: $year/$month"
              echo "  Photo date: $photo_date"
              echo "  No valid date found in filename. Defaulting to directory date."
            fi
          fi
        fi
      fi
    done
  done

  # Ask for confirmation before proceeding to the next year
  read -rp "Finished processing year $year. Do you want to save the changes and continue to the next year? (y/n): " response
  if [[ "$response" != "y" ]]; then
    echo "Stopping script."
    rm -f "$temp_file"
    touch "$temp_file"
    exit 0
  else
    # Apply changes and save log
    while IFS= read -r line; do
      if [[ "$line" == File:* ]]; then
        photo=$(echo "$line" | cut -d' ' -f2-)
      elif [[ "$line" == "  New Date:"* ]]; then
        new_date=$(echo "$line" | cut -d' ' -f3-)
        if ! exiftool -overwrite_original -DateTimeOriginal="$new_date" "$photo"; then
          handle_conversion_error "$photo"
        fi
      elif [[ "$line" == "  Suggested action: Move to"* ]]; then
        target_directory=$(echo "$line" | cut -d' ' -f4-)
        target_path="$base_dir/$target_directory"
        echo "$target_path"
        mkdir -p "$target_path" && mv "$photo" "$target_path/"
      fi
    done <"$temp_file"

    cat "$temp_file" >>"$log_file"
    rm -f "$temp_file"
    touch "$temp_file"
  fi
done
