import { describe, expect, it } from 'vitest';
import {
  CLASS_FRAMEWORK_ANNOTATIONS_FEATURE,
  findAnalysisFeatureMismatches,
  resolveAnalysisFeatureVersions,
  type AnalysisFeatureDescriptor,
} from '../../src/core/analysis-features.js';
import {
  SPRING_AOP_FEATURE,
  SPRING_BEAN_INVENTORY_FEATURE,
  SPRING_CONDITIONALS_FEATURE,
  SPRING_NON_HTTP_HANDLERS_FEATURE,
} from '../../src/core/ingestion/frameworks/spring/analysis-features.js';
import {
  JAVA_ENUM_INTERFACE_HERITAGE_FEATURE,
  JAVA_RECORD_COMPONENT_ACCESSORS_FEATURE,
  SPRING_CONFIG_BINDINGS_FEATURE,
} from '../../src/core/ingestion/languages/java/analysis-features.js';

const FEATURES = [
  CLASS_FRAMEWORK_ANNOTATIONS_FEATURE,
  SPRING_AOP_FEATURE,
  SPRING_BEAN_INVENTORY_FEATURE,
  SPRING_CONDITIONALS_FEATURE,
  SPRING_NON_HTTP_HANDLERS_FEATURE,
  SPRING_CONFIG_BINDINGS_FEATURE,
  JAVA_ENUM_INTERFACE_HERITAGE_FEATURE,
  JAVA_RECORD_COMPONENT_ACCESSORS_FEATURE,
] as const;

describe('analysis feature versions', () => {
  it('separates the global Class schema capability from JVM-only Bean evidence', () => {
    expect(resolveAnalysisFeatureVersions(FEATURES, ['src/app.ts'])).toEqual({
      'graph.class-framework-annotations': 1,
    });
    expect(resolveAnalysisFeatureVersions(FEATURES, ['src/App.java'])).toEqual({
      'graph.class-framework-annotations': 1,
      'java.heritage-captures': 1,
      'java.record-component-accessors': 1,
      'spring.aop-advice': 1,
      'spring.bean-inventory': 2,
      'spring.conditionals-auto-configuration': 1,
      'spring.config-bindings': 1,
      'spring.non-http-handlers': 1,
    });
    expect(resolveAnalysisFeatureVersions(FEATURES, ['BUILD.GRADLE.KTS'])).toEqual({
      'graph.class-framework-annotations': 1,
      'spring.aop-advice': 1,
      'spring.bean-inventory': 2,
      'spring.conditionals-auto-configuration': 1,
      'spring.non-http-handlers': 1,
    });
    expect(
      resolveAnalysisFeatureVersions(FEATURES, [
        'src/main/resources/application-local.yml',
        'README.md',
      ]),
    ).toEqual({
      'graph.class-framework-annotations': 1,
      'spring.config-bindings': 1,
    });
    expect(
      resolveAnalysisFeatureVersions(FEATURES, [
        'src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports',
      ]),
    ).toEqual({
      'graph.class-framework-annotations': 1,
      'spring.conditionals-auto-configuration': 1,
    });
  });

  it('requires an exact, well-formed feature set', () => {
    const expected = {
      'graph.class-framework-annotations': 1,
      'spring.bean-inventory': 2,
    };

    expect(findAnalysisFeatureMismatches(expected, expected)).toEqual([]);
    expect(findAnalysisFeatureMismatches(undefined, expected)).toEqual([
      'missing:graph.class-framework-annotations',
      'missing:spring.bean-inventory',
    ]);
    expect(
      findAnalysisFeatureMismatches(
        { 'graph.class-framework-annotations': 1, 'spring.bean-inventory': 1 },
        expected,
      ),
    ).toEqual(['version:spring.bean-inventory']);
    expect(findAnalysisFeatureMismatches({ feature: 1 }, { feature: 2 })).toEqual([
      'version:feature',
    ]);
    expect(
      findAnalysisFeatureMismatches({ ...expected, 'spring.future-feature': 1 }, expected),
    ).toEqual(['unexpected:spring.future-feature']);
    expect(findAnalysisFeatureMismatches([], expected)).toEqual(['invalid:analysisFeatures']);
    expect(findAnalysisFeatureMismatches({ ...expected, toString: 1 }, expected)).toEqual([
      'unexpected:toString',
    ]);
  });

  it('rejects invalid or duplicate descriptors', () => {
    const invalid: AnalysisFeatureDescriptor = {
      id: 'invalid',
      version: 0,
      appliesTo: () => true,
    };
    expect(() => resolveAnalysisFeatureVersions([invalid], [])).toThrow('invalid version');
    expect(() =>
      resolveAnalysisFeatureVersions(
        [CLASS_FRAMEWORK_ANNOTATIONS_FEATURE, CLASS_FRAMEWORK_ANNOTATIONS_FEATURE],
        [],
      ),
    ).toThrow('Duplicate analysis feature descriptor');
    expect(() =>
      resolveAnalysisFeatureVersions(
        [
          CLASS_FRAMEWORK_ANNOTATIONS_FEATURE,
          { ...CLASS_FRAMEWORK_ANNOTATIONS_FEATURE, appliesTo: () => false },
        ],
        [],
      ),
    ).toThrow('Duplicate analysis feature descriptor');
  });
});
