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

# Refresh Claude Code plugin caches for directory-source marketplaces.
# Discovers installed plugins from each local marketplace and refreshes their caches.
#
# Usage:
#   bin/refresh-plugins [marketplace-names...]
#   bin/refresh-plugins                    # refresh all local marketplaces
#   bin/refresh-plugins local-plugins      # refresh only local-plugins
#   bin/refresh-plugins cc-plugins local-plugins

require 'json'
require 'pathname'

class PluginRefresher
  attr_reader :results

  def initialize
    @results = []
  end

  def refresh(marketplace_names = nil)
    marketplaces = load_marketplaces(marketplace_names)

    marketplaces.each do |name, config|
      next unless config['source']['source'] == 'directory'

      puts "Refreshing marketplace: #{name}"
      refresh_marketplace(name, config)
      puts
    end

    report_results
  end

  private

  def load_marketplaces(names)
    all = JSON.parse(File.read(File.expand_path('~/.claude/plugins/known_marketplaces.json')))
    return all unless names

    all.select { |k, _| names.include?(k) }
  end

  def refresh_marketplace(marketplace_name, config)
    source_path = config['source']['path']
    installed = load_installed_plugins(marketplace_name)

    installed.each do |plugin_name|
      refresh_plugin(marketplace_name, plugin_name, source_path)
    end
  end

  def load_installed_plugins(marketplace_name)
    all = JSON.parse(File.read(File.expand_path('~/.claude/plugins/installed_plugins.json')))
    all['plugins']
      .select { |k, _| k.end_with?("@#{marketplace_name}") }
      .keys
      .map { |k| k.sub(/@#{marketplace_name}$/, '') }
      .uniq
  end

  def refresh_plugin(marketplace_name, plugin_name, source_path)
    cache_exists = cache_exists?(marketplace_name, plugin_name)

    unless File.exist?(File.join(source_path, plugin_name))
      @results << [plugin_name, "source not found at #{source_path}", :error]
      puts "  #{plugin_name}: ERROR — source not found"
      return
    end

    system("claude plugin uninstall #{plugin_name}@#{marketplace_name} > /dev/null 2>&1")
    system("claude plugin install #{plugin_name}@#{marketplace_name} > /dev/null 2>&1")

    if verify_cache(marketplace_name, plugin_name, source_path)
      @results << [plugin_name, "refreshed", :success]
      puts "  #{plugin_name}: REFRESHED"
    elsif !cache_exists
      @results << [plugin_name, "in-sync (not previously cached)", :info]
      puts "  #{plugin_name}: IN SYNC (new)"
    else
      @results << [plugin_name, "STALE", :warning]
      puts "  #{plugin_name}: STALE (differences remain)"
    end
  end

  def cache_exists?(marketplace_name, plugin_name)
    Dir.exist?(File.expand_path("~/.claude/plugins/cache/#{marketplace_name}/#{plugin_name}"))
  end

  def verify_cache(marketplace_name, plugin_name, source_path)
    cache_base = File.expand_path("~/.claude/plugins/cache/#{marketplace_name}/#{plugin_name}")
    source_full = File.join(source_path, plugin_name)

    # Find the version directory in cache
    versions = Dir.glob(File.join(cache_base, '*')).select { |p| File.directory?(p) }
    return false if versions.empty?

    cache_path = versions.first

    # Run diff check (exclude plugin manager state files)
    output = `diff -rq "#{cache_path}" "#{source_full}" --exclude='.git' --exclude='__pycache__' --exclude='.orphaned_at' 2>&1`
    output.strip.empty?
  end

  def report_results
    puts "\n=== Summary ==="
    successes = @results.select { |_, _, status| status == :success }
    warnings = @results.select { |_, _, status| status == :warning }
    errors = @results.select { |_, _, status| status == :error }
    infos = @results.select { |_, _, status| status == :info }

    puts "Refreshed: #{successes.map { |r| r[0] }.join(', ')}" if successes.any?
    puts "In sync: #{infos.map { |r| r[0] }.join(', ')}" if infos.any?
    puts "Stale (not fixed): #{warnings.map { |r| r[0] }.join(', ')}" if warnings.any?
    puts "Errors: #{errors.map { |r| "#{r[0]} (#{r[1]})" }.join(', ')}" if errors.any?
    puts "All plugins synchronized." if @results.all? { |_, _, s| s != :warning && s != :error }
  end
end

marketplace_names = ARGV.empty? ? nil : ARGV
PluginRefresher.new.refresh(marketplace_names)
