name: Validate Plugins

on:
  pull_request:
    paths:
      - 'plugins/**'
      - '.claude-plugin/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Validate marketplace.json
        run: |
          MARKETPLACE=".claude-plugin/marketplace.json"

          if [ ! -f "$MARKETPLACE" ]; then
            echo "::error::marketplace.json not found at $MARKETPLACE"
            exit 1
          fi

          if ! jq empty "$MARKETPLACE" 2>/dev/null; then
            echo "::error::marketplace.json is not valid JSON"
            exit 1
          fi

          # Check required fields
          for field in name description plugins; do
            if [ "$(jq -r ".$field // empty" "$MARKETPLACE")" = "" ]; then
              echo "::error::marketplace.json missing required field: $field"
              exit 1
            fi
          done

          # Check for duplicate plugin names
          DUPES=$(jq -r '.plugins[].name' "$MARKETPLACE" | sort | uniq -d)
          if [ -n "$DUPES" ]; then
            echo "::error::Duplicate plugin names in marketplace.json: $DUPES"
            exit 1
          fi

          echo "✓ marketplace.json is valid"

      - name: Validate plugin.json files
        run: |
          ERRORS=0
          PLUGIN_ROOT="./plugins"

          for plugin_dir in "$PLUGIN_ROOT"/*/; do
            plugin_name=$(basename "$plugin_dir")
            plugin_json="$plugin_dir/.claude-plugin/plugin.json"

            if [ ! -f "$plugin_json" ]; then
              echo "::error::Missing plugin.json for $plugin_name at $plugin_json"
              ERRORS=$((ERRORS + 1))
              continue
            fi

            if ! jq empty "$plugin_json" 2>/dev/null; then
              echo "::error::$plugin_json is not valid JSON"
              ERRORS=$((ERRORS + 1))
              continue
            fi

            # Check name matches directory
            JSON_NAME=$(jq -r '.name' "$plugin_json")
            if [ "$JSON_NAME" != "$plugin_name" ]; then
              echo "::error::plugin.json name '$JSON_NAME' does not match directory '$plugin_name'"
              ERRORS=$((ERRORS + 1))
            fi

            # Check valid semver
            VERSION=$(jq -r '.version' "$plugin_json")
            if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
              echo "::error::$plugin_name plugin.json version '$VERSION' is not valid semver"
              ERRORS=$((ERRORS + 1))
            fi

            # Check description present
            DESC=$(jq -r '.description // empty' "$plugin_json")
            if [ -z "$DESC" ]; then
              echo "::error::$plugin_name plugin.json missing description"
              ERRORS=$((ERRORS + 1))
            fi

            echo "✓ $plugin_name plugin.json is valid"
          done

          if [ $ERRORS -gt 0 ]; then
            echo "::error::$ERRORS plugin.json validation error(s)"
            exit 1
          fi

      - name: Validate SKILL.md files
        run: |
          ERRORS=0
          WARNINGS=0

          while IFS= read -r skill_file; do
            skill_dir=$(dirname "$skill_file")
            skill_name=$(basename "$skill_dir")

            # Check frontmatter exists
            FIRST_LINE=$(head -1 "$skill_file")
            if [ "$FIRST_LINE" != "---" ]; then
              echo "::error file=$skill_file::SKILL.md missing YAML frontmatter (must start with ---)"
              ERRORS=$((ERRORS + 1))
              continue
            fi

            # Extract frontmatter
            FRONTMATTER=$(sed -n '1,/^---$/{ /^---$/d; p; }' "$skill_file" | tail -n +1)

            # Check description in frontmatter
            if ! echo "$FRONTMATTER" | grep -q '^description:'; then
              echo "::error file=$skill_file::SKILL.md frontmatter missing description field"
              ERRORS=$((ERRORS + 1))
            fi

            # Check name matches directory if set
            FM_NAME=$(echo "$FRONTMATTER" | grep '^name:' | sed 's/^name: *//')
            if [ -n "$FM_NAME" ] && [ "$FM_NAME" != "$skill_name" ]; then
              echo "::error file=$skill_file::SKILL.md name '$FM_NAME' does not match directory '$skill_name'"
              ERRORS=$((ERRORS + 1))
            fi

            # Line count warning
            LINES=$(wc -l < "$skill_file")
            if [ "$LINES" -gt 500 ]; then
              echo "::warning file=$skill_file::SKILL.md is $LINES lines (recommended: under 500)"
              WARNINGS=$((WARNINGS + 1))
            fi

            echo "✓ $skill_file ($LINES lines)"
          done < <(find plugins -name "SKILL.md" -type f)

          if [ $ERRORS -gt 0 ]; then
            echo "::error::$ERRORS SKILL.md validation error(s)"
            exit 1
          fi
          echo "$WARNINGS warning(s)"

      - name: Validate agent files
        run: |
          ERRORS=0

          while IFS= read -r agent_file; do
            FIRST_LINE=$(head -1 "$agent_file")
            if [ "$FIRST_LINE" != "---" ]; then
              echo "::error file=$agent_file::Agent file missing YAML frontmatter"
              ERRORS=$((ERRORS + 1))
              continue
            fi

            FRONTMATTER=$(sed -n '1,/^---$/{ /^---$/d; p; }' "$agent_file" | tail -n +1)

            if ! echo "$FRONTMATTER" | grep -q '^name:'; then
              echo "::error file=$agent_file::Agent frontmatter missing name field"
              ERRORS=$((ERRORS + 1))
            fi

            if ! echo "$FRONTMATTER" | grep -q '^description:'; then
              echo "::error file=$agent_file::Agent frontmatter missing description field"
              ERRORS=$((ERRORS + 1))
            fi

            echo "✓ $agent_file"
          done < <(find plugins -path "*/agents/*.md" -type f 2>/dev/null)

          if [ $ERRORS -gt 0 ]; then
            echo "::error::$ERRORS agent validation error(s)"
            exit 1
          fi

      - name: Check marketplace completeness
        run: |
          ERRORS=0
          PLUGIN_ROOT="./plugins"

          for plugin_dir in "$PLUGIN_ROOT"/*/; do
            plugin_name=$(basename "$plugin_dir")
            IN_MARKETPLACE=$(jq -r --arg name "$plugin_name" '.plugins[] | select(.name == $name) | .name' .claude-plugin/marketplace.json)
            if [ -z "$IN_MARKETPLACE" ]; then
              echo "::error::Plugin directory '$plugin_name' has no entry in marketplace.json"
              ERRORS=$((ERRORS + 1))
            fi
          done

          if [ $ERRORS -gt 0 ]; then
            exit 1
          fi
          echo "✓ All plugin directories have marketplace.json entries"

      - name: Check release-please registration
        run: |
          ERRORS=0
          PLUGIN_ROOT="./plugins"
          CONFIG="release-please-config.json"
          MANIFEST=".release-please-manifest.json"

          for plugin_dir in "$PLUGIN_ROOT"/*/; do
            plugin_name=$(basename "$plugin_dir")
            plugin_path="plugins/$plugin_name"

            # Check release-please-config.json
            IN_CONFIG=$(jq -r --arg path "$plugin_path" '.packages[$path] // empty' "$CONFIG")
            if [ -z "$IN_CONFIG" ]; then
              echo "::error::Plugin '$plugin_name' is not registered in $CONFIG — release-please won't create tags/releases for it"
              ERRORS=$((ERRORS + 1))
            fi

            # Check .release-please-manifest.json
            IN_MANIFEST=$(jq -r --arg path "$plugin_path" '.[$path] // empty' "$MANIFEST")
            if [ -z "$IN_MANIFEST" ]; then
              echo "::error::Plugin '$plugin_name' is not registered in $MANIFEST — add it with initial version"
              ERRORS=$((ERRORS + 1))
            fi
          done

          if [ $ERRORS -gt 0 ]; then
            echo "::error::$ERRORS release-please registration error(s). Every plugin must be in both $CONFIG and $MANIFEST."
            exit 1
          fi
          echo "✓ All plugins are registered in release-please config and manifest"

      - name: Check script path references
        run: |
          WARNINGS=0

          while IFS= read -r skill_file; do
            skill_dir=$(dirname "$skill_file")
            if [ -d "$skill_dir/scripts" ]; then
              # Check for bare scripts/ references without ${CLAUDE_SKILL_DIR}
              if grep -n 'scripts/' "$skill_file" | grep -v 'CLAUDE_SKILL_DIR' | grep -v '^[0-9]*:#' | grep -qv '^\-\-\-'; then
                echo "::warning file=$skill_file::Found bare scripts/ reference without \${CLAUDE_SKILL_DIR}"
                WARNINGS=$((WARNINGS + 1))
              fi
            fi
          done < <(find plugins -name "SKILL.md" -type f)

          echo "$WARNINGS warning(s)"
