package linthost

import (
  "sort"
  "testing"
)

// TestFormatBlockTargetsOptionAcceptingRules verifies every formatter payload
// produced by the public format block lands on a structurally option-accepting
// rule, and every registered formatter is represented.
//
// Format settings are expanded into ordinary rule tuples before engine
// construction. This includes an empty object for rules that need no fields,
// so inferring acceptance only from DecodeOptions calls would reject a valid
// default format run. Deriving both sets from the live expansion and registry
// keeps the boundary free of a second formatter-name list.
//
//  1. Expand a format block with the opt-in sort rule enabled.
//  2. Parse its generated option payloads and compare them with registered
//     format rules.
//  3. Assert every generated target reports AcceptsTtscLintOptions.
//
// @evidence contracts/testing.md#behavioral-verification expandFormatBlock and ParseRulesWithOptions generate a payload for every live built-in formatter, and each resolved rule structurally accepts options.
// @evidence contracts/testing.md#independent-expectations The independently registered live formatter set and public option-acceptance capability constrain the generated payload set; this verifies runtime configuration compatibility rather than committed-file parity.
// @evidence contracts/testing.md#distinguishing-cases Owns default formatter expansion plus opt-in import sorting, missing registrations, optionless targets and either-direction set mismatch; it does not substitute for individual formatter behavior tests.
// @evidence contracts/testing.md#execution-ownership This discoverable Go entry owns the case described above. Direct expandFormatBlock and ParseRulesWithOptions calls compare runtime payload targets with AllRuleNames/LookupRule capabilities in-process; no committed source-file scan or native compilation participates in the compatibility oracle.
func TestFormatBlockTargetsOptionAcceptingRules(t *testing.T) {
  expanded, err := expandFormatBlock(map[string]any{"sortImports": true})
  if err != nil {
    t.Fatal(err)
  }
  _, options, err := ParseRulesWithOptions(expanded)
  if err != nil {
    t.Fatal(err)
  }

  registeredFormat := map[string]struct{}{}
  for _, name := range AllRuleNames() {
    if isRegisteredBuiltInFormatRule(name, LookupRule(name)) {
      registeredFormat[name] = struct{}{}
    }
  }
  generated := make(map[string]struct{}, len(options))
  for name := range options {
    generated[name] = struct{}{}
    rule := LookupRule(name)
    if rule == nil {
      t.Errorf("format block generated payload for unregistered rule %q", name)
      continue
    }
    if !ruleAcceptsOptions(rule) {
      t.Errorf("format block generated payload for optionless rule %q", name)
    }
  }
  assertSameRuleNameSet(t, "registered format rules", registeredFormat, "generated format payloads", generated)
}

func assertSameRuleNameSet(
  t *testing.T,
  leftLabel string,
  left map[string]struct{},
  rightLabel string,
  right map[string]struct{},
) {
  t.Helper()
  var onlyLeft, onlyRight []string
  for name := range left {
    if _, ok := right[name]; !ok {
      onlyLeft = append(onlyLeft, name)
    }
  }
  for name := range right {
    if _, ok := left[name]; !ok {
      onlyRight = append(onlyRight, name)
    }
  }
  sort.Strings(onlyLeft)
  sort.Strings(onlyRight)
  if len(onlyLeft) > 0 || len(onlyRight) > 0 {
    t.Fatalf(
      "%s and %s differ: only %s=%v; only %s=%v",
      leftLabel,
      rightLabel,
      leftLabel,
      onlyLeft,
      rightLabel,
      onlyRight,
    )
  }
}
