# frozen_string_literal: true

require_relative 'test_helper'

# ─── Enable ───────────────────────────────────────────────────────────────────

class TestEnable < Minitest::Test
  include TestHelpers

  def setup
    setup_temp_dirs
  end

  def teardown
    teardown_temp_dirs
  end

  def test_enable_new_plugin_creates_file_and_adds_entry
    op = make_operation(PluginConfig::Operations::Enable)
    result = op.call

    assert_includes %w[created_and_enabled enabled], result[:status]
    assert_equal 'test-plugin@test-marketplace', result[:plugin]
    assert result[:verified], 'Expected verified to be true'
    assert_includes result[:enabled_plugins], 'test-plugin@test-marketplace'
  end

  def test_enable_adds_to_existing_settings
    create_settings('other-plugin@other-marketplace' => true)

    op = make_operation(PluginConfig::Operations::Enable)
    result = op.call

    assert_equal 'enabled', result[:status]
    assert_includes result[:enabled_plugins], 'other-plugin@other-marketplace'
    assert_includes result[:enabled_plugins], 'test-plugin@test-marketplace'
  end

  def test_enable_already_enabled_returns_already_enabled
    create_settings('test-plugin@test-marketplace' => true)

    op = make_operation(PluginConfig::Operations::Enable)
    result = op.call

    assert_equal 'already_enabled', result[:status]
    assert result[:verified]
  end

  def test_enabled_plugins_sorted_alphabetically
    create_settings('z-plugin@z-marketplace' => true, 'a-plugin@a-marketplace' => true)

    op = make_operation(PluginConfig::Operations::Enable)
    result = op.call

    expected = ['a-plugin@a-marketplace', 'test-plugin@test-marketplace', 'z-plugin@z-marketplace']
    assert_equal expected, result[:enabled_plugins]
  end

  def test_verified_flag_is_true_on_success
    op = make_operation(PluginConfig::Operations::Enable)
    result = op.call

    assert result[:verified]
  end
end

# ─── Disable ──────────────────────────────────────────────────────────────────

class TestDisable < Minitest::Test
  include TestHelpers

  def setup
    setup_temp_dirs
  end

  def teardown
    teardown_temp_dirs
  end

  def test_disable_existing_plugin_removes_entry
    create_settings('test-plugin@test-marketplace' => true)

    op = make_operation(PluginConfig::Operations::Disable)
    result = op.call

    assert_equal 'disabled', result[:status]
    refute_includes result[:remaining_plugins], 'test-plugin@test-marketplace'
  end

  def test_disable_nonexistent_plugin_returns_not_found
    create_settings({})

    op = make_operation(PluginConfig::Operations::Disable)
    result = op.call

    assert_equal 'not_found', result[:status]
  end

  def test_disable_preserves_other_plugins
    create_settings(
      'test-plugin@test-marketplace' => true,
      'keep-me@other' => true
    )

    op = make_operation(PluginConfig::Operations::Disable)
    result = op.call

    assert_equal 'disabled', result[:status]
    assert_includes result[:remaining_plugins], 'keep-me@other'
    refute_includes result[:remaining_plugins], 'test-plugin@test-marketplace'
  end

  def test_verified_flag_confirms_key_absent
    create_settings('test-plugin@test-marketplace' => true)

    op = make_operation(PluginConfig::Operations::Disable)
    result = op.call

    assert result[:verified]
  end
end

# ─── Register ─────────────────────────────────────────────────────────────────

class TestRegister < Minitest::Test
  include TestHelpers

  def setup
    setup_temp_dirs
  end

  def teardown
    teardown_temp_dirs
  end

  def test_register_new_plugin_adds_to_marketplace
    create_marketplace(plugins: [])

    op = make_operation(PluginConfig::Operations::Register, description: 'A test plugin')
    result = op.call

    assert_equal 'registered', result[:status]
    assert result[:verified]

    data = JSON.parse(File.read(marketplace_path))
    names = data['plugins'].map { |p| p['name'] }
    assert_includes names, 'test-plugin'
  end

  def test_register_already_present_returns_already_registered
    create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])

    op = make_operation(PluginConfig::Operations::Register)
    result = op.call

    assert_equal 'already_registered', result[:status]
    assert result[:verified]
  end

  def test_plugins_array_sorted_by_name
    create_marketplace(plugins: [{ 'name' => 'z-plugin', 'source' => './z-plugin', 'description' => '' }])

    op = make_operation(PluginConfig::Operations::Register, plugin: 'a-plugin')
    result = op.call

    data = JSON.parse(File.read(marketplace_path))
    names = data['plugins'].map { |p| p['name'] }
    assert_equal %w[a-plugin z-plugin], names
  end

  def test_description_is_stored_correctly
    create_marketplace(plugins: [])

    op = make_operation(PluginConfig::Operations::Register, description: 'My description')
    result = op.call

    data = JSON.parse(File.read(marketplace_path))
    plugin_entry = data['plugins'].find { |p| p['name'] == 'test-plugin' }
    assert_equal 'My description', plugin_entry['description']
  end
end

# ─── Unregister ───────────────────────────────────────────────────────────────

class TestUnregister < Minitest::Test
  include TestHelpers

  def setup
    setup_temp_dirs
  end

  def teardown
    teardown_temp_dirs
  end

  def test_unregister_existing_plugin
    create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])

    op = make_operation(PluginConfig::Operations::Unregister)
    result = op.call

    assert_equal 'unregistered', result[:status]
    assert result[:verified]

    data = JSON.parse(File.read(marketplace_path))
    names = data['plugins'].map { |p| p['name'] }
    refute_includes names, 'test-plugin'
  end

  def test_unregister_nonexistent_returns_not_found
    create_marketplace(plugins: [])

    op = make_operation(PluginConfig::Operations::Unregister)
    result = op.call

    assert_equal 'not_found', result[:status]
  end

  def test_unregister_preserves_other_plugins
    create_marketplace(plugins: [
      { 'name' => 'keep-me', 'source' => './keep-me', 'description' => '' },
      { 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }
    ])

    op = make_operation(PluginConfig::Operations::Unregister)
    result = op.call

    data = JSON.parse(File.read(marketplace_path))
    names = data['plugins'].map { |p| p['name'] }
    assert_includes names, 'keep-me'
    refute_includes names, 'test-plugin'
  end
end

# ─── Audit ────────────────────────────────────────────────────────────────────

class TestAudit < Minitest::Test
  include TestHelpers

  def setup
    setup_temp_dirs
    # Create installed_plugins in temp location; override the path
    @installed_path = File.join(@tmpdir, 'installed_plugins.json')
  end

  def teardown
    teardown_temp_dirs
  end

  def test_clean_state_returns_ok
    # Create all required files with correct entries
    create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])
    create_settings('test-plugin@test-marketplace' => true)

    # Need to stub installed_plugins_path - create a subclass
    op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } })
    result = op.call

    assert_equal 'ok', result[:status]
    assert_empty result[:issues]
  end

  def test_missing_marketplace_entry_reports_issue_with_fix
    create_marketplace(plugins: [])  # plugin not registered
    create_settings('test-plugin@test-marketplace' => true)

    op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } })
    result = op.call

    assert_equal 'issues_found', result[:status]
    marketplace_check = result[:checks][:marketplace]
    assert_equal 'issue', marketplace_check[:status]
    assert marketplace_check[:fix]
  end

  def test_missing_settings_entry_reports_issue_with_fix
    create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }])
    create_settings({})  # plugin not enabled

    op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } })
    result = op.call

    assert_equal 'issues_found', result[:status]
    settings_check = result[:checks][:settings]
    assert_equal 'issue', settings_check[:status]
    assert settings_check[:fix]
  end

  def test_multiple_issues_all_reported
    create_marketplace(plugins: [])  # not registered
    create_settings({})              # not enabled

    op = make_audit_op_with_installed({})  # not installed
    result = op.call

    assert_equal 'issues_found', result[:status]
    assert result[:issues].length >= 2, "Expected at least 2 issues, got #{result[:issues].length}"
  end

  private

  # Create an Audit subclass that overrides installed_plugins_path to use temp dir
  def make_audit_op_with_installed(installed_plugins)
    installed_path = @installed_path
    create_installed_plugins(installed_path, installed_plugins)

    params = {
      plugin: 'test-plugin',
      marketplace: 'test-marketplace',
      project: @project_dir,
      marketplace_file: marketplace_path
    }

    op = PluginConfig::Operations::Audit.new(params)
    # Override the installed_plugins_path method
    op.define_singleton_method(:installed_plugins_path) { installed_path }
    op
  end
end

# ─── List ─────────────────────────────────────────────────────────────────────

class TestList < Minitest::Test
  include TestHelpers

  def setup
    setup_temp_dirs
  end

  def teardown
    teardown_temp_dirs
  end

  def test_list_returns_all_enabled_plugins
    create_settings(
      'b-plugin@marketplace' => true,
      'a-plugin@marketplace' => true
    )

    op = make_operation(PluginConfig::Operations::List)
    result = op.call

    assert_equal 'ok', result[:status]
    assert_equal %w[a-plugin@marketplace b-plugin@marketplace], result[:enabled_plugins]
    assert_equal 2, result[:count]
  end

  def test_list_empty_settings_returns_empty_array
    create_settings({})

    op = make_operation(PluginConfig::Operations::List)
    result = op.call

    assert_equal 'ok', result[:status]
    assert_empty result[:enabled_plugins]
    assert_equal 0, result[:count]
  end

  def test_list_missing_file_returns_empty_array
    # Don't create settings file
    op = make_operation(PluginConfig::Operations::List)
    result = op.call

    assert_equal 'ok', result[:status]
    assert_empty result[:enabled_plugins]
    assert_equal 0, result[:count]
  end
end
