#!/bin/bash
set -euo pipefail

# Changelog generation script for packwiz modpacks
# Converts old PowerShell changelog generation to bash

# Default values
RELEASE_VERSION=""
CURSEFORGE_PROJECT_ID=""
CURSEFORGE_FILE_ID=""
MODLISTCREATOR_VERSION="5.0.0"
BUILDS_FOLDER="builds"
FORCE_MODLIST=false

# Print usage information
usage() {
    cat << EOF
Usage: $0 [OPTIONS]

Generate changelog by comparing current modpack with previous CurseForge release.

Options:
    -v, --version VERSION        Release version (required)
    -p, --project-id ID         CurseForge project ID (required)
    -i, --file-id ID            Specific CurseForge file ID to compare against (optional)
    -m, --modlistcreator VER    ModListCreator version (default: $MODLISTCREATOR_VERSION)
    -b, --builds-dir DIR        Builds directory (default: $BUILDS_FOLDER)
    -f, --force-modlist         Force modlist generation even if previous release exists
    -h, --help                  Show this help message

Examples:
    # Generate changelog for new version (uses latest CurseForge release)
    $0 --version "1.7.4" --project-id "1188525"
    
    # Generate changelog against specific file ID
    $0 --version "1.7.4" --project-id "1188525" --file-id "5123456"
    
    # Use specific ModListCreator version
    $0 --version "1.7.4" --project-id "1188525" --modlistcreator "4.0.0"
EOF
}

# Parse command line arguments
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -v|--version)
                RELEASE_VERSION="$2"
                shift 2
                ;;
            -p|--project-id)
                CURSEFORGE_PROJECT_ID="$2"
                shift 2
                ;;
            -i|--file-id)
                CURSEFORGE_FILE_ID="$2"
                shift 2
                ;;
            -m|--modlistcreator)
                MODLISTCREATOR_VERSION="$2"
                shift 2
                ;;
            -b|--builds-dir)
                BUILDS_FOLDER="$2"
                shift 2
                ;;
            -f|--force-modlist)
                FORCE_MODLIST=true
                shift
                ;;
            -h|--help)
                usage
                exit 0
                ;;
            *)
                echo "Unknown option: $1" >&2
                usage >&2
                exit 1
                ;;
        esac
    done

    # Validate required arguments
    if [[ -z "$RELEASE_VERSION" ]]; then
        echo "Error: Release version is required" >&2
        usage >&2
        exit 1
    fi

    if [[ -z "$CURSEFORGE_PROJECT_ID" ]]; then
        echo "Error: CurseForge project ID is required" >&2
        usage >&2
        exit 1
    fi
}

# Ensure ModListCreator exists, download if needed
ensure_modlistcreator() {
    local jar_file="automation/ModListCreator-${MODLISTCREATOR_VERSION}-fatjar.jar"
    
    if [[ ! -f "$jar_file" ]]; then
        echo "Downloading ModListCreator..." >&2
        mkdir -p automation
        
        local download_url="https://github.com/ModdingX/ModListCreator/releases/download/${MODLISTCREATOR_VERSION}/ModListCreator-${MODLISTCREATOR_VERSION}-fatjar.jar"
        
        if ! curl -sSL -o "$jar_file" "$download_url"; then
            echo "Error: Failed to download ModListCreator" >&2
            exit 1
        fi
        
        echo "Downloaded ModListCreator to $jar_file" >&2
    fi
    
    echo "$jar_file"
}

# Get latest release from CurseForge API
get_latest_curseforge_release() {
    local project_id="$1"
    local api_url="https://www.curseforge.com/api/v1/mods/${project_id}/files"
    
    echo "Fetching latest release from CurseForge..." >&2
    echo "API URL: $api_url" >&2
    
    # Call CurseForge API and extract latest release version
    local response
    if ! response=$(curl -sSL -f "$api_url"); then
        echo "Error: Failed to fetch CurseForge API data" >&2
        echo "Response: $response" >&2
        return 1
    fi
    
    echo "API response received, parsing..." >&2
    
    # Parse JSON and find latest release (releaseType = 1)
    local latest_release
    if command -v jq &> /dev/null; then
        echo "Using jq for JSON parsing" >&2
        latest_release=$(echo "$response" | jq -r '.data[] | select(.releaseType == 1) | [.dateCreated, .id, .fileName] | @tsv' | sort -r | head -1)
    else
        echo "Using sed fallback for JSON parsing" >&2
        # Fallback without jq (basic parsing, may not be as robust)
        latest_release=$(echo "$response" | grep -o '"releaseType":1[^}]*"fileName":"[^"]*"[^}]*"id":[0-9]*' | head -1 | \
        sed 's/.*"fileName":"\([^"]*\)".*"id":\([0-9]*\).*/\1\t\2/')
    fi
    
    if [[ -n "$latest_release" ]]; then
        echo "Found latest release: $latest_release" >&2
        echo "$latest_release"
    else
        echo "No release found in API response" >&2
        return 1
    fi
}

# Download previous release file
download_previous_release() {
    local project_id="$1"
    local file_id="$2"
    local output_file="$3"
    
    echo "Downloading previous release file ID: $file_id" >&2
    
    # Ensure the builds directory exists
    mkdir -p "$(dirname "$output_file")"
    
    # First try to get the actual download URL from the file metadata
    echo "Getting file metadata for ID: $file_id" >&2
    local file_info_url="https://www.curseforge.com/api/v1/mods/${project_id}/files/${file_id}"
    local file_info
    
    if file_info=$(curl -sSL -f "$file_info_url" 2>/dev/null); then
        echo "Got file metadata" >&2
        
        # Try to extract direct download URL from metadata
        local direct_url
        if command -v jq &> /dev/null; then
            direct_url=$(echo "$file_info" | jq -r '.data.downloadUrl // empty')
        else
            direct_url=$(echo "$file_info" | grep -o '"downloadUrl":"[^"]*"' | sed 's/.*"downloadUrl":"\([^"]*\)".*/\1/')
        fi
        
        if [[ -n "$direct_url" && "$direct_url" != "null" ]]; then
            echo "Using direct download URL: $direct_url" >&2
            if curl -sSL -f --create-dirs -o "$output_file" "$direct_url"; then
                if [[ -f "$output_file" && -s "$output_file" ]]; then
                    echo "Downloaded previous release to $output_file ($(stat -c%s "$output_file") bytes)" >&2
                    return 0
                fi
            fi
        fi
    fi
    
    echo "Trying standard download URL..." >&2
    local download_url="https://www.curseforge.com/api/v1/mods/${project_id}/files/${file_id}/download"
    
    echo "Download URL: $download_url" >&2
    echo "Output file: $output_file" >&2
    
    # Try the download with more verbose output and follow redirects
    if curl -sSL -f --create-dirs -o "$output_file" "$download_url"; then
        # Verify the file was downloaded and is not empty
        if [[ -f "$output_file" && -s "$output_file" ]]; then
            echo "Downloaded previous release to $output_file ($(stat -c%s "$output_file") bytes)" >&2
            return 0
        else
            echo "Error: Downloaded file is empty or missing" >&2
            rm -f "$output_file"
        fi
    else
        echo "Error: Failed to download previous release from $download_url" >&2
    fi
    
    echo "Trying alternative download method..." >&2
    
    # Alternative: Try direct CurseForge download URL format
    # CurseForge uses a pattern where file ID 1234567 becomes /files/1234/567/filename
    local alt_url="https://edge.forgecdn.net/files/${file_id:0:4}/${file_id:4}/$(basename "$output_file")"
    echo "Alternative URL: $alt_url" >&2
    
    if curl -sSL -f --create-dirs -o "$output_file" "$alt_url"; then
        if [[ -f "$output_file" && -s "$output_file" ]]; then
            echo "Downloaded previous release via alternative method to $output_file ($(stat -c%s "$output_file") bytes)" >&2
            return 0
        fi
    fi
    
    echo "Error: All download methods failed" >&2
    rm -f "$output_file"
    return 1
}

# Generate manifest.json from current packwiz setup
generate_manifest() {
    echo "Generating manifest.json from current setup..." >&2
    
    if ! command -v packwiz &> /dev/null; then
        echo "Error: packwiz command not found" >&2
        exit 1
    fi
    
    # Use packwiz to generate a manifest - this creates a temporary export and extracts the manifest
    local temp_export="temp-export-$$.zip"
    
    if packwiz curseforge export --output "$temp_export"; then
        # Extract manifest.json from the export
        if unzip -q -j "$temp_export" "manifest.json" -d .; then
            rm -f "$temp_export"
            echo "Generated manifest.json" >&2
        else
            rm -f "$temp_export"
            echo "Error: Failed to extract manifest.json from packwiz export" >&2
            exit 1
        fi
    else
        echo "Error: Failed to create packwiz export" >&2
        exit 1
    fi
}

# Generate changelog using ModListCreator
generate_changelog() {
    local release_version="$1"
    local has_previous_release="$2"
    local modlistcreator_jar="$3"
    
    if [[ ! -f "$modlistcreator_jar" ]]; then
        echo "Error: ModListCreator jar not found: $modlistcreator_jar" >&2
        exit 1
    fi
    
    local manifest_file="manifest.json"
    local output_file="${BUILDS_FOLDER}/changelog.md"
    local previous_file="${BUILDS_FOLDER}/previous.zip"
    
    # Ensure builds directory exists
    mkdir -p "$BUILDS_FOLDER"
    
    # Check if Java is available
    if ! command -v java &> /dev/null; then
        echo "Error: Java is required to run ModListCreator" >&2
        exit 1
    fi
    
    if [[ "$has_previous_release" == "true" && ! "$FORCE_MODLIST" == "true" ]]; then
        echo "Generating changelog..." >&2
        java -jar "$modlistcreator_jar" changelog \
            --old "$previous_file" \
            --new "$manifest_file" \
            --output "$output_file" \
            --no-header
    else
        echo "Generating modlist..." >&2
        java -jar "$modlistcreator_jar" modlist \
            --output "$output_file" \
            --no-header \
            "$manifest_file"
    fi
    
    echo "Generated changelog at $output_file" >&2
}

# Main function
main() {
    parse_args "$@"
    
    echo "Generating changelog for version: $RELEASE_VERSION"
    echo "CurseForge Project ID: $CURSEFORGE_PROJECT_ID"
    if [[ -n "$CURSEFORGE_FILE_ID" ]]; then
        echo "Comparing against specific file ID: $CURSEFORGE_FILE_ID"
    else
        echo "Comparing against latest CurseForge release"
    fi
    echo ""
    
    # Download ModListCreator if needed
    local modlistcreator_jar
    modlistcreator_jar=$(ensure_modlistcreator)
    
    # Generate current manifest
    generate_manifest
    
    # Get previous release for comparison
    local has_previous_release="false"
    local previous_release=""
    local file_id=""
    local filename=""
    
    if [[ -n "$CURSEFORGE_FILE_ID" ]]; then
        # Use specific file ID provided by user
        echo "Using specific file ID: $CURSEFORGE_FILE_ID"
        file_id="$CURSEFORGE_FILE_ID"
        
        # Try to get filename from file metadata
        echo "Getting file metadata for specified file ID..." >&2
        local file_info_url="https://www.curseforge.com/api/v1/mods/${CURSEFORGE_PROJECT_ID}/files/${file_id}"
        local file_info
        
        if file_info=$(curl -sSL -f "$file_info_url" 2>/dev/null); then
            if command -v jq &> /dev/null; then
                filename=$(echo "$file_info" | jq -r '.data.fileName // "unknown"')
            else
                filename=$(echo "$file_info" | grep -o '"fileName":"[^"]*"' | sed 's/.*"fileName":"\([^"]*\)".*/\1/' || echo "unknown")
            fi
            echo "File metadata found: $filename"
        else
            echo "Warning: Could not get metadata for file ID $file_id, using generic filename"
            filename="previous-release.zip"
        fi
        
        previous_release="found"
    else
        # Get latest release from CurseForge
        echo "Fetching latest release from CurseForge..."
        if previous_release=$(get_latest_curseforge_release "$CURSEFORGE_PROJECT_ID"); then
            if [[ -n "$previous_release" ]]; then
                # Parse the tab-separated response
                if command -v jq &> /dev/null; then
                    # If we used jq, we have date, id, filename
                    file_id=$(echo "$previous_release" | cut -f2)
                    filename=$(echo "$previous_release" | cut -f3)
                else
                    # If we used sed fallback, we have filename, id
                    filename=$(echo "$previous_release" | cut -f1)
                    file_id=$(echo "$previous_release" | cut -f2)
                fi
                echo "Found latest release: $filename (ID: $file_id)"
            fi
        fi
    fi
    
    # Download the comparison file if we have one
    if [[ -n "$previous_release" && -n "$file_id" && -n "$filename" ]]; then
        echo "Current comparison release: $filename"
        
        # Download previous release
        if download_previous_release "$CURSEFORGE_PROJECT_ID" "$file_id" "${BUILDS_FOLDER}/previous.zip"; then
            has_previous_release="true"
        fi
    fi
    
    if [[ "$has_previous_release" == "false" ]]; then
        if [[ -n "$CURSEFORGE_FILE_ID" ]]; then
            echo "Could not download specified file ID $CURSEFORGE_FILE_ID, will generate modlist instead of changelog"
        else
            echo "No previous release found, will generate modlist instead of changelog"
        fi
    fi
    
    # Generate changelog or modlist
    generate_changelog "$RELEASE_VERSION" "$has_previous_release" "$modlistcreator_jar"
    
    # Cleanup
    rm -f manifest.json
    
    echo ""
    echo "Changelog generation completed successfully!"
    echo "Output saved to: ${BUILDS_FOLDER}/changelog.md"
}

# Run main function with all arguments
main "$@"
