#!/usr/bin/env bash
set -euo pipefail
# lanekeep migrate — modernize lanekeep.json. Two passes:
#   1. Monolithic config → layered (`{"extends": "defaults", ...}`).
#   2. Legacy `rule_overrides` / `disabled_rules` → canonical `overrides` block (1.1).

LANEKEEP_DIR="$(cd "$(dirname "$0")/.." && pwd)"
PROJECT_DIR="${1:-$(pwd 2>/dev/null || echo "$PWD")}"
CONFIG="$PROJECT_DIR/lanekeep.json"
[ -f "$CONFIG" ] || [ ! -f "$PROJECT_DIR/lanekeep.json.bak" ] || CONFIG="$PROJECT_DIR/lanekeep.json.bak"
DEFAULTS="$LANEKEEP_DIR/defaults/lanekeep.json"

if [ ! -f "$CONFIG" ]; then
  echo "No lanekeep.json found in $PROJECT_DIR" >&2
  exit 1
fi

# Detect layering and presence of legacy override keys
extends=$(jq -r '.extends // empty' "$CONFIG" 2>/dev/null) || true
has_legacy=$(jq -r '
  if ((.rule_overrides // []) | length > 0) or ((.disabled_rules // []) | length > 0)
  then "yes" else "" end
' "$CONFIG" 2>/dev/null) || has_legacy=""

OUTPUT="$CONFIG.new"

if [ "$extends" = "defaults" ]; then
  if [ -z "$has_legacy" ]; then
    echo "Already using layered config with no legacy override keys — nothing to migrate." >&2
    exit 0
  fi

  # Pass 2: layered + legacy override keys → layered with canonical overrides block.
  jq '
    .overrides = (
      (.overrides // {}) +
      ((.rule_overrides // []) | map({(.id): (del(.id))}) | add // {}) +
      ((.disabled_rules // []) | map({(.): {"disabled": true}}) | add // {})
    )
    | del(.rule_overrides, .disabled_rules)
    | if (.overrides | length) == 0 then del(.overrides) else . end
  ' "$CONFIG" > "$OUTPUT"

  n_overrides=$(jq '.overrides // {} | length' "$OUTPUT")
  echo "Converted legacy override keys to \"overrides\" block: $OUTPUT"
  echo "  $n_overrides entries in overrides"
  echo ""
  echo "Review $OUTPUT, then:"
  echo "  mv $OUTPUT $CONFIG"
  exit 0
fi

# Pass 1: monolithic config → layered with extends + overrides + extra_rules.
override=$(jq -s '
  .[0] as $defaults | .[1] as $user |

  # Find user rules that differ from defaults (by content, not position)
  ($user.rules // []) as $user_rules |
  ($defaults.rules // []) as $default_rules |

  # Rules that exist in defaults but user changed
  [($default_rules | to_entries[] |
    select(.value | has("id")) |
    .value as $dr |
    ($user_rules | map(select(.id == $dr.id and . != $dr)) | first // null) as $changed |
    if $changed != null then $changed else empty end
  )] as $diffed |

  # Rules in user that are NOT in defaults (by id or content)
  [$user_rules[] |
    . as $ur |
    if has("id") then
      if ($default_rules | map(select(.id == $ur.id)) | length) == 0 then $ur else empty end
    else
      if ($default_rules | map(select(. == $ur)) | length) == 0 then $ur else empty end
    end
  ] as $extras |

  # Non-rules fields that differ from defaults
  (($user | del(.rules)) as $u | ($defaults | del(.rules)) as $d |
    [$u | to_entries[] | select(
      .key as $k | .value as $v |
      if ($d | has($k)) then ($d[$k] != $v) else true end
    )] | from_entries
  ) as $field_overrides |

  # Build minimal config — 1.1: emit canonical "overrides" object keyed by rule-id
  {"extends": "defaults"} +
  $field_overrides +
  (if ($diffed | length) > 0 then {"overrides": ($diffed | map({(.id): (del(.id))}) | add)} else {} end) +
  (if ($extras | length) > 0 then {"extra_rules": $extras} else {} end)
' "$DEFAULTS" "$CONFIG" 2>/dev/null)

if [ -z "$override" ]; then
  echo "Error: failed to compute diff" >&2
  exit 1
fi

printf '%s\n' "$override" | jq '.' > "$OUTPUT"

n_overrides=$(printf '%s' "$override" | jq '.overrides // {} | length')
n_extras=$(printf '%s' "$override" | jq '.extra_rules // [] | length')
n_fields=$(printf '%s' "$override" | jq 'del(.extends, .overrides, .extra_rules) | length')

echo "Generated layered config: $OUTPUT"
echo "  extends: defaults"
echo "  $n_fields field overrides"
echo "  $n_overrides rule overrides"
echo "  $n_extras extra rules"
echo ""
echo "Review $OUTPUT, then:"
echo "  mv $OUTPUT $CONFIG"
