#!/usr/bin/env nu
# Fix MD013 line length errors by wrapping long lines at natural break points

def wrap-line [line: string, max_len: int]: string -> string {
    let len = $line | str length

    # Skip if line is short enough
    if $len <= $max_len {
        return $line
    }

    # Skip table rows (can't easily wrap)
    if ($line | str trim | str starts-with "|") {
        return $line
    }

    # Skip code blocks (shouldn't wrap)
    if ($line | str trim | str starts-with "```") {
        return $line
    }

    # Skip heading lines
    if ($line | str trim | str starts-with "#") {
        return $line
    }

    # Skip list items that start with - or *
    let trimmed = $line | str trim
    if ($trimmed | str starts-with "- ") or ($trimmed | str starts-with "* ") or ($trimmed =~ '^\d+\. ') {
        # List items - try to wrap at sentence boundaries
        return (wrap-at-punctuation $line $max_len)
    }

    # Regular prose - wrap at sentence or clause boundaries
    wrap-at-punctuation $line $max_len
}

def wrap-at-punctuation [line: string, max_len: int]: string -> string {
    let len = $line | str length
    if $len <= $max_len {
        return $line
    }

    # Find the last space before max_len that follows punctuation or a good break point
    let break_points = [". " ", " "; " ": " "- " "— " " and " " or " " but " " which " " that " " when " " where "]

    mut best_pos = -1
    for bp in $break_points {
        # Find positions of this break point
        let positions = find-all-positions $line $bp
        for pos in $positions {
            # Check if this position is valid (before max_len but not too early)
            let break_at = $pos + ($bp | str length)
            if $break_at <= $max_len and $break_at > $best_pos and $break_at > 50 {
                $best_pos = $break_at
            }
        }
    }

    # If no good break point found, fall back to last space before max_len
    if $best_pos == -1 {
        let spaces = find-all-positions $line " "
        for pos in ($spaces | reverse) {
            if $pos < $max_len and $pos > 40 {
                $best_pos = $pos + 1
                break
            }
        }
    }

    # If still no break point, return as-is (can't wrap safely)
    if $best_pos == -1 {
        return $line
    }

    # Split at best position
    let first = $line | str substring 0..$best_pos | str trim-end
    let rest = $line | str substring $best_pos..
    let rest_trimmed = $rest | str trim-start

    # Return wrapped result
    $"($first)\n($rest_trimmed)"
}

def find-all-positions [text: string, pattern: string]: list<int> {
    mut positions = []
    mut start = 0
    let text_len = $text | str length
    let pattern_len = $pattern | str length

    while $start < ($text_len - $pattern_len) {
        let sub = $text | str substring $start..($start + $pattern_len)
        if $sub == $pattern {
            $positions = ($positions | append $start)
        }
        $start = $start + 1
    }

    $positions
}

def process-file [file: path, max_len: int] {
    let content = open $file --raw
    let lines = $content | lines

    mut in_code_block = false
    mut new_lines = []

    for line in $lines {
        # Track code blocks
        if ($line | str trim | str starts-with "```") {
            $in_code_block = not $in_code_block
            $new_lines = ($new_lines | append $line)
            continue
        }

        # Don't process lines inside code blocks
        if $in_code_block {
            $new_lines = ($new_lines | append $line)
            continue
        }

        # Wrap long lines
        let wrapped = wrap-line $line $max_len
        # Split wrapped result back into lines
        let wrapped_lines = $wrapped | lines
        $new_lines = ($new_lines | append $wrapped_lines)
    }

    let new_content = $new_lines | str join "\n"
    $new_content | save -f $file
}

def main [
    file?: path        # Specific file to process (optional)
    --max-len: int = 150  # Maximum line length
    --dry-run (-d)     # Show what would be changed without modifying files
] {
    if $file != null {
        print $"Processing: ($file)"
        process-file $file $max_len
    } else {
        # Get files with MD013 errors from markdownlint
        print "Getting files with MD013 errors..."
        let result = (markdownlint-cli2 --config .markdownlint-cli2.jsonc "**/*.md" | complete)
        let errors = $result.stderr | lines | where { $in | str contains "MD013" }
        let files = $errors | each { $in | split row ":" | first } | uniq

        print $"Found ($files | length) files with MD013 errors"

        for f in $files {
            if $dry_run {
                print $"Would fix: ($f)"
            } else {
                print $"Fixing: ($f)"
                process-file $f $max_len
            }
        }
    }

    print "Done"
}
