# Cargo.toml Diff Analyzer Library
# Provides functions to compare Cargo.toml files and categorize changes

# Parse a Cargo.toml file and extract dependency information
export def parse_cargo_toml [file_path: string] {
    if not ($file_path | path exists) {
        error make {msg: $"File not found: ($file_path)"}
    }

    let content = open $file_path
    let dependencies = try {
        $content | get dependencies? | default {}
    } catch {
        {}
    }

    let dev_dependencies = try {
        $content | get dev-dependencies? | default {}
    } catch {
        {}
    }

    let build_dependencies = try {
        $content | get build-dependencies? | default {}
    } catch {
        {}
    }

    {
        package: ($content | get package? | default {}),
        dependencies: $dependencies,
        dev_dependencies: $dev_dependencies,
        build_dependencies: $build_dependencies,
        raw_content: $content
    }
}

# Extract nu-* dependencies from parsed Cargo.toml
export def extract_nu_dependencies [parsed_cargo: record] {
    let all_deps = ($parsed_cargo.dependencies | transpose key value)

    $all_deps
    | where $it.key =~ "^nu-"
    | reduce -f {} {|dep, acc|
        $acc | upsert $dep.key $dep.value
    }
}

# Compare two Cargo.toml files and categorize differences
export def compare_cargo_tomls [local_path: string, upstream_path: string] {
    let local = parse_cargo_toml $local_path
    let upstream = parse_cargo_toml $upstream_path

    let local_nu_deps = extract_nu_dependencies $local
    let upstream_nu_deps = extract_nu_dependencies $upstream

    # Find all dependency differences
    let all_local_deps = $local.dependencies | transpose key value
    let all_upstream_deps = $upstream.dependencies | transpose key value

    # Dependencies only in local
    let local_only = $all_local_deps
    | where {|dep|
        not ($all_upstream_deps | any {|up| $up.key == $dep.key})
    }

    # Dependencies only in upstream
    let upstream_only = $all_upstream_deps
    | where {|dep|
        not ($all_local_deps | any {|loc| $loc.key == $dep.key})
    }

    # Dependencies with different versions
    let version_diffs = $all_local_deps
    | where {|local_dep|
        let upstream_dep = $all_upstream_deps | where key == $local_dep.key | first
        if ($upstream_dep | is-empty) {
            false
        } else {
            $local_dep.value != $upstream_dep.value
        }
    }
    | each {|dep|
        let upstream_ver = $all_upstream_deps | where key == $dep.key | first | get value
        {
            dependency: $dep.key,
            local_version: $dep.value,
            upstream_version: $upstream_ver,
            is_nu_dependency: ($dep.key =~ "^nu-")
        }
    }

    # Check if only nu-* dependencies differ
    let non_nu_changes = $version_diffs | where not $it.is_nu_dependency
    let only_nu_deps_changed = (($local_only | length) == 0) and (($upstream_only | length) == 0) and (($non_nu_changes | length) == 0)

    # Package version comparison
    let package_diff = if ($local.package.version? != null) and ($upstream.package.version? != null) {
        if $local.package.version != $upstream.package.version {
            {
                local_version: $local.package.version,
                upstream_version: $upstream.package.version
            }
        } else {
            null
        }
    } else {
        null
    }

    {
        dependencies: {
            local_only: $local_only,
            upstream_only: $upstream_only,
            version_differences: $version_diffs
        },
        package: {
            version_diff: $package_diff
        },
        analysis: {
            only_nu_deps_changed: $only_nu_deps_changed,
            nu_deps_changed: ($version_diffs | where $it.is_nu_dependency),
            non_nu_deps_changed: $non_nu_changes,
            has_changes: ((($version_diffs | length) > 0) or (($local_only | length) > 0) or (($upstream_only | length) > 0) or ($package_diff != null))
        }
    }
}

# Check if changes are safe for auto-OK based on nu dependencies only
export def is_safe_for_auto_ok [diff_result: record, nu_managed_deps: list<string>] {
    let analysis = $diff_result.analysis

    # Must have changes to be relevant
    if not $analysis.has_changes {
        return false
    }

    # Check if all changed dependencies are in the managed list
    let all_changed_deps = $analysis.nu_deps_changed | get dependency
    let all_managed = $all_changed_deps | all {|dep| $dep in $nu_managed_deps}

    # Safe if only nu deps changed AND all changed deps are managed
    $analysis.only_nu_deps_changed and $all_managed
}

# Generate a human-readable diff summary
export def generate_diff_summary [diff_result: record] {
    let analysis = $diff_result.analysis

    if not $analysis.has_changes {
        return "No changes detected"
    }

    mut summary = []

    # Package version changes
    if ($diff_result.package.version_diff != null) {
        let pkg_diff = $diff_result.package.version_diff
        $summary = ($summary | append $"Package version: ($pkg_diff.local_version) → ($pkg_diff.upstream_version)")
    }

    # Nu dependency changes
    if ($analysis.nu_deps_changed | length) > 0 {
        let nu_changes = $analysis.nu_deps_changed
        | each {|dep| $"  ($dep.dependency): ($dep.local_version) → ($dep.upstream_version)"}
        | str join "\n"
        $summary = ($summary | append $"Nu dependencies:\n($nu_changes)")
    }

    # Non-nu dependency changes
    if ($analysis.non_nu_deps_changed | length) > 0 {
        let other_changes = $analysis.non_nu_deps_changed
        | each {|dep| $"  ($dep.dependency): ($dep.local_version) → ($dep.upstream_version)"}
        | str join "\n"
        $summary = ($summary | append $"Other dependencies:\n($other_changes)")
    }

    # New dependencies
    if ($diff_result.dependencies.upstream_only | length) > 0 {
        let new_deps = $diff_result.dependencies.upstream_only
        | each {|dep| $"  ($dep.key): ($dep.value)"}
        | str join "\n"
        $summary = ($summary | append $"New dependencies:\n($new_deps)")
    }

    # Removed dependencies
    if ($diff_result.dependencies.local_only | length) > 0 {
        let removed_deps = $diff_result.dependencies.local_only
        | each {|dep| $"  ($dep.key): ($dep.value)"}
        | str join "\n"
        $summary = ($summary | append $"Removed dependencies:\n($removed_deps)")
    }

    $summary | str join "\n\n"
}