#!/usr/bin/env nu

# Download Nushell Source Script
# Downloads and extracts Nushell source from GitHub tags
#
# Usage:
#   download_nushell.nu <version>        # Download specific version
#   download_nushell.nu --latest         # Download latest release
#   download_nushell.nu --clean          # Remove existing nushell directory

use lib/common_lib.nu *

# Main entry point
def main [
    version?: string          # Nushell version (e.g., "0.108.0")
    --latest                  # Download latest release
    --clean                   # Remove existing nushell directory first
    --verify                  # Verify download integrity
] {
    log_info "Nushell Source Download Script"

    # Determine target version
    let target_version = if $latest {
        get_latest_nushell_version
    } else if ($version | is-empty) {
        log_error "Please specify a version or use --latest flag"
        log_info "Usage: download_nushell.nu <version> or download_nushell.nu --latest"
        exit 1
    } else {
        $version
    }

    log_info $"Target version: ($target_version)"

    # Check if nushell directory already exists with correct version
    let nushell_dir = "./nushell"
    if ($nushell_dir | path exists) and (not $clean) {
        let cargo_toml = $"($nushell_dir)/Cargo.toml"
        if ($cargo_toml | path exists) {
            let existing_version = (try {
                open $cargo_toml | get package.version
            } catch {
                ""
            })

            if $existing_version == $target_version {
                log_success $"Nushell ($target_version) already exists - skipping download"
                log_info "Use --clean flag to force re-download"
                return
            } else {
                log_warn $"Found different version: ($existing_version) - will download ($target_version)"
            }
        }
    }

    # Clean existing directory if requested
    if $clean {
        clean_nushell_directory
    }

    # Download and extract
    download_nushell_tarball $target_version $verify

    # Verify extraction
    verify_nushell_source $target_version

    log_success $"Nushell ($target_version) downloaded and ready!"
    log_info $"Location: ./nushell/"
    log_info $"Next steps: Run 'just analyze-nushell-features' to check available features"
}

# Get latest nushell version from GitHub API
def get_latest_nushell_version []: nothing -> string {
    log_info "Fetching latest Nushell version from GitHub..."

    let api_url = "https://api.github.com/repos/nushell/nushell/releases/latest"

    let response = try {
        http get $api_url
    } catch {
        log_error "Failed to fetch latest release from GitHub API"
        log_info "Falling back to manual check at: https://github.com/nushell/nushell/releases"
        exit 1
    }

    let tag_name = try {
        $response | get tag_name | str trim
    } catch {
        log_error "Could not parse tag_name from GitHub response"
        exit 1
    }

    # Remove 'v' prefix if present
    let version = $tag_name | str replace "^v" ""

    log_success $"Latest version: ($version)"
    $version
}

# Clean existing nushell directory
def clean_nushell_directory [] {
    let nushell_dir = "./nushell"

    if ($nushell_dir | path exists) {
        log_warn "Removing existing nushell directory..."
        rm -rf $nushell_dir
        log_success "Cleaned nushell directory"
    } else {
        log_info "No existing nushell directory to clean"
    }
}

# Download nushell tarball from GitHub
def download_nushell_tarball [
    version: string
    verify_checksum: bool
] {
    let tarball_url = $"https://github.com/nushell/nushell/archive/refs/tags/($version).tar.gz"
    let download_dir = "./tmp"
    let tarball_path = $"($download_dir)/nushell-($version).tar.gz"

    # Ensure tmp directory exists
    ensure_dir $download_dir

    # Download tarball
    log_info $"Downloading from: ($tarball_url)"

    let download_result = try {
        http get $tarball_url | save -f $tarball_path
        {success: true}
    } catch { |err|
        {success: false, error: $err}
    }

    if not $download_result.success {
        log_error $"Failed to download tarball from GitHub"
        log_info $"URL: ($tarball_url)"
        exit 1
    }

    # Check file was downloaded
    if not ($tarball_path | path exists) {
        log_error $"Tarball not found at ($tarball_path)"
        exit 1
    }

    let file_size = (ls $tarball_path | get size.0)
    log_success $"Downloaded tarball: ($file_size) bytes"

    # Verify checksum if requested
    if $verify_checksum {
        verify_download_checksum $tarball_path $version
    }

    # Extract tarball
    extract_nushell_tarball $tarball_path $version
}

# Verify download checksum (optional)
def verify_download_checksum [
    tarball_path: string
    version: string
] {
    log_info "Calculating SHA256 checksum..."

    let checksum = open $tarball_path --raw | hash sha256
    log_info $"Checksum: ($checksum)"

    # Note: GitHub doesn't provide checksums for source archives
    # This is just for verification and logging
    log_warn "GitHub source archives don't have published checksums"
    log_info "Checksum calculated for local verification only"
}

# Extract nushell tarball
def extract_nushell_tarball [
    tarball_path: string
    version: string
] {
    log_info "Extracting tarball..."

    let tmp_extract_dir = "./tmp/nushell-extract"
    ensure_dir $tmp_extract_dir

    # Extract to temp directory
    let extract_result = try {
        ^tar -xzf $tarball_path -C $tmp_extract_dir
        {success: true}
    } catch { |err|
        {success: false, error: $err}
    }

    if not $extract_result.success {
        log_error "Failed to extract tarball"
        exit 1
    }

    # GitHub creates a directory like "nushell-0.108.0"
    let extracted_dir = $"($tmp_extract_dir)/nushell-($version)"

    if not ($extracted_dir | path exists) {
        log_error $"Expected directory not found: ($extracted_dir)"
        log_info "Checking available directories..."
        ls $tmp_extract_dir | each {|it| log_info $"  Found: ($it.name)"}
        exit 1
    }

    # Move to final location
    let target_dir = "./nushell"
    if ($target_dir | path exists) {
        log_warn "Target directory already exists, removing..."
        rm -rf $target_dir
    }

    mv $extracted_dir $target_dir
    log_success $"Extracted to: ($target_dir)"

    # Cleanup
    rm -rf $tmp_extract_dir
    rm $tarball_path
    log_info "Cleaned up temporary files"
}

# Verify nushell source was extracted correctly
def verify_nushell_source [
    version: string
] {
    log_info "Verifying nushell source..."

    let nushell_dir = "./nushell"
    let cargo_toml = $"($nushell_dir)/Cargo.toml"

    # Check main Cargo.toml exists
    if not ($cargo_toml | path exists) {
        log_error $"Cargo.toml not found at ($cargo_toml)"
        exit 1
    }

    # Verify version in Cargo.toml
    let cargo_version = try {
        open $cargo_toml | get package.version
    } catch {
        log_error "Could not read version from Cargo.toml"
        exit 1
    }

    if $cargo_version != $version {
        log_warn $"Version mismatch: Cargo.toml shows ($cargo_version], expected ($version)"
        log_info "This might be normal if the version doesn't exactly match the tag"
    } else {
        log_success $"Version verified: ($cargo_version)"
    }

    # Check workspace structure
    let workspace_members = try {
        open $cargo_toml | get workspace.members
    } catch {
        log_error "Could not read workspace members from Cargo.toml"
        exit 1
    }

    let member_count = $workspace_members | length
    log_success $"Found ($member_count) workspace members"

    # Check for system plugins
    let system_plugins = $workspace_members | where {|it| $it | str starts-with "crates/nu_plugin_"}
    let plugin_count = $system_plugins | length
    log_info $"System plugins: ($plugin_count)"

    # List system plugins
    if $plugin_count > 0 {
        log_info "System plugins found:"
        $system_plugins | each {|plugin|
            let plugin_name = $plugin | str replace "crates/" ""
            log_info $"  • ($plugin_name)"
        }
    }
}

# Show current nushell source info
def "main info" [] {
    let nushell_dir = "./nushell"

    if not ($nushell_dir | path exists) {
        log_error "Nushell source not found"
        log_info "Run: download_nushell.nu <version>"
        exit 1
    }

    let cargo_toml = $"($nushell_dir)/Cargo.toml"
    let version = open $cargo_toml | get package.version

    log_info "Nushell Source Information"
    log_info $"  Version: ($version)"
    log_info $"  Location: ($nushell_dir)"

    let workspace_members = open $cargo_toml | get workspace.members
    let member_count = $workspace_members | length
    log_info $"  Workspace members: ($member_count)"

    let system_plugins = $workspace_members | where {|it| $it | str starts-with "crates/nu_plugin_"}
    log_info $"  System plugins: ($system_plugins | length)"
}

# Clean up downloaded files
def "main clean" [] {
    clean_nushell_directory

    let tmp_dir = "./tmp"
    if ($tmp_dir | path exists) {
        rm -rf $tmp_dir
        log_success "Removed tmp directory"
    }
}
