#!/usr/bin/env ruby
# frozen_string_literal: true

# Cross-repo marketplace acceptance script.
#
# For one or more marketplace roots (repos containing a
# .claude-plugin/marketplace.json), runs the plugin_config validate
# operation against every plugin the marketplace declares and reports a
# pass/fail table plus totals.
#
# Usage:
#   ruby validate_marketplaces.rb <marketplace-root>...
#
# With no arguments, prints usage (including the documented default
# invocation for this machine) and exits 2.
#
# Exit status:
#   0  every plugin in every given marketplace passed validation
#   1  at least one plugin failed validation
#   2  usage error (no args, missing/invalid marketplace.json, etc.)

require 'json'
require 'open3'

SCRIPT_DIR = File.expand_path(__dir__)
PLUGIN_CONFIG_RB = File.join(SCRIPT_DIR, 'plugin_config', 'plugin_config.rb')

DEFAULT_MARKETPLACE_ROOTS = [
  '/home/jared/dev/cc-plugins',
  '/home/jared/dev/cc-os'
].freeze

def usage
  <<~USAGE
    Usage: ruby #{File.basename(__FILE__)} <marketplace-root>...

    Each <marketplace-root> is a repo root containing
    .claude-plugin/marketplace.json. Every plugin declared in that
    marketplace is validated with the plugin_config `validate` operation,
    against that marketplace's manifest.

    Documented default invocation for this machine:
      ruby #{__FILE__} #{DEFAULT_MARKETPLACE_ROOTS.join(' ')}
  USAGE
end

# Runs `plugin_config.rb validate` for a single plugin and returns the
# parsed JSON result (or a synthetic failure result if the subprocess
# couldn't be run or produced unparseable output).
def validate_plugin(plugin_path, marketplace_file)
  cmd = [
    'ruby', PLUGIN_CONFIG_RB, 'validate',
    "--plugin_path=#{plugin_path}",
    "--marketplace_file=#{marketplace_file}"
  ]
  stdout, stderr, _status = Open3.capture3(*cmd)

  begin
    JSON.parse(stdout, symbolize_names: true)
  rescue JSON::ParserError
    {
      status: 'issues_found',
      valid: false,
      plugin_path: plugin_path,
      checks: {},
      issues: ["validator produced unparseable output: #{stdout.strip}#{stderr.strip}"]
    }
  end
end

# Validates every plugin declared by one marketplace root. Returns
# { root:, plugin_results: [{name:, plugin_path:, valid:, issues: []}], error: nil|String }
def validate_marketplace(root)
  abs_root = File.expand_path(root)
  marketplace_file = File.join(abs_root, '.claude-plugin', 'marketplace.json')

  unless File.exist?(marketplace_file)
    return { root: abs_root, marketplace_file: marketplace_file, plugin_results: [], error: "marketplace.json not found at #{marketplace_file}" }
  end

  data = begin
    JSON.parse(File.read(marketplace_file))
  rescue JSON::ParserError => e
    return { root: abs_root, marketplace_file: marketplace_file, plugin_results: [], error: "invalid JSON in #{marketplace_file}: #{e.message}" }
  end

  plugins = data['plugins'] || []
  if plugins.empty?
    return { root: abs_root, marketplace_file: marketplace_file, plugin_results: [], error: "no plugins declared in #{marketplace_file}" }
  end

  plugin_results = plugins.map do |entry|
    name = entry['name']
    source = entry['source']
    plugin_path = source ? File.expand_path(source, abs_root) : nil

    if plugin_path.nil?
      { name: name || '(unnamed)', plugin_path: nil, valid: false, issues: ['marketplace entry has no source field'] }
    else
      result = validate_plugin(plugin_path, marketplace_file)
      {
        name: name || '(unnamed)',
        plugin_path: plugin_path,
        valid: result[:valid] == true,
        issues: Array(result[:issues])
      }
    end
  end

  { root: abs_root, marketplace_file: marketplace_file, plugin_results: plugin_results, error: nil }
end

def print_report(marketplace_reports)
  total_plugins = 0
  total_failed = 0

  marketplace_reports.each do |report|
    puts "== #{report[:root]} =="

    if report[:error]
      puts "  ERROR: #{report[:error]}"
      puts
      next
    end

    report[:plugin_results].each do |pr|
      total_plugins += 1
      if pr[:valid]
        puts "  PASS  #{pr[:name]}"
      else
        total_failed += 1
        first_issue = pr[:issues].first
        summary = first_issue ? first_issue.to_s.lines.first.to_s.strip : '(no issue detail)'
        puts "  FAIL  #{pr[:name]} - #{summary}"
      end
    end
    puts
  end

  [total_plugins, total_failed]
end

def main(argv)
  if argv.empty?
    puts usage
    exit 2
  end

  marketplace_reports = argv.map { |root| validate_marketplace(root) }

  total_plugins, total_failed = print_report(marketplace_reports)

  hard_error = marketplace_reports.any? { |r| r[:error] }

  puts "TOTAL: #{total_plugins} plugin(s) checked, #{total_plugins - total_failed} passed, #{total_failed} failed"

  if hard_error
    exit 2
  elsif total_failed.positive?
    exit 1
  else
    exit 0
  end
end

main(ARGV) if __FILE__ == $PROGRAM_NAME
