#!/usr/bin/env bash

# format-markdown.sh
# Author: Matthew Raymer
# Date: 2025-07-09
# Description: Format markdown files to comply with project markdown ruleset
# Enhanced: Auto-fix, parallel lint, summary, CI-friendly, multi-linter support
# Always fixes missing blank lines around headings.

set -e

# Fix missing blank lines above and below headings in a Markdown file
fix_blank_lines_around_headings() {
  local file="$1"
  awk '
    BEGIN { prev=""; }
    {
      if ($0 ~ /^#{1,6} /) {
        if (NR > 1 && prev != "") print "";
        print $0;
        getline nextline;
        if (nextline != "") print "";
        print nextline;
        prev = nextline;
        next;
      }
      print $0;
      prev = $0;
    }
  ' "$file" > "$file.tmp" && mv "$file.tmp" "$file"
}

show_help() {
  echo "Usage: $0 [--fix] [--ci] [--linter <markdownlint|prettier|both>] <file-or-directory> [more files...]"
  echo "Formats and lints markdown files."
  echo "Options:"
  echo "  -h, --help         Show this help message"
  echo "  --fix             Auto-fix lint errors (if supported)"
  echo "  --ci              CI-friendly output (machine-readable)"
  echo "  --linter <type>   Choose linter: markdownlint, prettier, or both (default: both)"
  echo "  <file-or-directory>  Markdown files or directories to process"
  exit 0
}

# Default options
fix=0
ci=0
linter="both"
args=()

# Parse flags
while [[ $# -gt 0 ]]; do
  case "$1" in
    -h|--help) show_help ;;
    --fix) fix=1 ; shift ;;
    --ci) ci=1 ; shift ;;
    --linter) linter="$2" ; shift 2 ;;
    --) shift ; break ;;
    -*) echo "Unknown option: $1"; show_help ;;
    *) args+=("$1"); shift ;;
  esac
done

if [ ${#args[@]} -eq 0 ]; then
  show_help
fi

# Tool checks
for tool in awk sed; do
  if ! command -v $tool >/dev/null 2>&1; then
    echo "$tool is required but not installed. Exiting."
    exit 1
  fi
done

if ! command -v npx >/dev/null 2>&1; then
  echo "npx is required for linting. Exiting."
  exit 1
fi

# Check for prettier and markdownlint availability
has_prettier=0
has_markdownlint=0
if npx prettier --version >/dev/null 2>&1; then
  has_prettier=1
fi
if npx markdownlint --version >/dev/null 2>&1; then
  has_markdownlint=1
fi

# Respect .markdownlintignore if present
mlint_ignore=""
if [ -f .markdownlintignore ]; then
  mlint_ignore="--ignore-path .markdownlintignore"
fi

# Gather files
all_files=()
for target in "${args[@]}"; do
  if [ -d "$target" ]; then
    while IFS= read -r -d $'\0' file; do
      all_files+=("$file")
    done < <(find "$target" -type f -name "*.md" -print0)
  else
    all_files+=("$target")
  fi
done

# Remove duplicates
all_files=( $(printf "%s\n" "${all_files[@]}" | sort -u) )

# Format and lint files
lint_errors=0
failed_files=()
passed_files=()

format_and_lint() {
  file="$1"
  # Fix missing blank lines around headings
  fix_blank_lines_around_headings "$file"

  # Basic formatting
    sed -i 's/[[:space:]]*$//' "$file"
    awk 'NF{blank=0} !NF{blank++} blank<2' "$file" > "$file.tmp" && mv "$file.tmp" "$file"
    awk '1; END{if (NR && $0!="") print ""}' "$file" > "$file.tmp" && mv "$file.tmp" "$file"

  # Auto-fix with prettier
  if [[ $fix -eq 1 && ( "$linter" == "prettier" || "$linter" == "both" ) && $has_prettier -eq 1 ]]; then
    npx prettier --write "$file" >/dev/null 2>&1 && echo "Auto-fixed with prettier: $file"
  fi
  # Auto-fix with markdownlint
  if [[ $fix -eq 1 && ( "$linter" == "markdownlint" || "$linter" == "both" ) && $has_markdownlint -eq 1 ]]; then
    npx markdownlint --fix $mlint_ignore "$file" >/dev/null 2>&1 && echo "Auto-fixed with markdownlint: $file"
  fi

  # Linting
  lint_ok=1
  if [[ "$linter" == "prettier" || "$linter" == "both" ]] && [[ $has_prettier -eq 1 ]]; then
    if ! npx prettier --check "$file" >/dev/null 2>&1; then
      lint_ok=0
      echo "Prettier lint errors in $file"
    fi
  fi
  if [[ "$linter" == "markdownlint" || "$linter" == "both" ]] && [[ $has_markdownlint -eq 1 ]]; then
    if ! npx markdownlint $mlint_ignore "$file"; then
      lint_ok=0
      echo "Markdownlint errors in $file"
    fi
  fi
  if [[ $lint_ok -eq 1 ]]; then
    passed_files+=("$file")
    [[ $ci -eq 0 ]] && echo "PASS: $file"
  else
    failed_files+=("$file")
    lint_errors=1
    [[ $ci -eq 0 ]] && echo "FAIL: $file"
    [[ $ci -eq 1 ]] && echo "$file"
  fi
}

# Export for xargs
export -f format_and_lint
export fix linter has_prettier has_markdownlint mlint_ignore ci

# Run in parallel (4 at a time)
printf "%s\n" "${all_files[@]}" | xargs -n 1 -P 4 -I {} bash -c 'format_and_lint "$@"' _ {}

# Summary
if [[ $ci -eq 0 ]]; then
  echo
  echo "Lint summary:"
  echo "Passed: ${#passed_files[@]}"
  echo "Failed: ${#failed_files[@]}"
  if [ ${#failed_files[@]} -gt 0 ]; then
    printf '%s\n' "${failed_files[@]}"
  fi
fi

if [ $lint_errors -ne 0 ]; then
  echo "Some files have markdownlint or prettier errors. Please fix them."
  exit 1
fi

echo "Markdown formatting complete." 