package analysis

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"sync"
	"unicode"

	"github.com/dusk-network/pituitary/internal/config"
	"github.com/dusk-network/pituitary/internal/model"
	"github.com/dusk-network/pituitary/internal/resultmeta"
	"github.com/dusk-network/pituitary/internal/temporal"
	stindex "github.com/dusk-network/stroma/v3/index"
	"golang.org/x/sync/errgroup"
)

var (
	requestsPerMinutePattern = regexp.MustCompile(`(?i)(\d+)\s+requests per minute`)
	artifactReferencePattern = regexp.MustCompile(`(?i)[a-z0-9][a-z0-9._-]*\.(?:db|json|md|toml|yaml|yml)`)
)

const (
	driftClassificationSemantic = "semantic_contradiction"
	driftClassificationRole     = "role_mismatch"
	sourceRoleMetadataKey       = "source_role"
	docDriftRelevantSpecLimit   = 5
	docDriftSimilarityThreshold = 0.45
)

type docDocument struct {
	Record   model.DocRecord
	Sections []embeddedSection
}

// DocDriftRequest is the normalized doc-drift input.
type DocDriftRequest struct {
	DocRef        string   `json:"doc_ref,omitempty"`
	DocRefs       []string `json:"doc_refs,omitempty"`
	Scope         string   `json:"scope,omitempty"`
	DiffFile      string   `json:"diff_file,omitempty"`
	DiffText      string   `json:"diff_text,omitempty"`
	AtDate        string   `json:"at_date,omitempty"`
	MinConfidence string   `json:"min_confidence,omitempty"`
}

// DocDriftScope reports the normalized selector.
type DocDriftScope struct {
	Mode    string   `json:"mode"`
	DocRefs []string `json:"doc_refs"`
}

// DriftEvidence reports the concrete spec/doc sections that support one drift judgment.
type DriftEvidence struct {
	SpecRef       string `json:"spec_ref,omitempty"`
	SpecTitle     string `json:"spec_title,omitempty"`
	SpecSourceRef string `json:"spec_source_ref,omitempty"`
	SpecSection   string `json:"spec_section,omitempty"`
	SpecExcerpt   string `json:"spec_excerpt,omitempty"`
	DocSourceRef  string `json:"doc_source_ref,omitempty"`
	DocSection    string `json:"doc_section,omitempty"`
	DocExcerpt    string `json:"doc_excerpt,omitempty"`
	LinkReason    string `json:"link_reason,omitempty"`
}

// DriftConfidence reports how certain the analysis is about one judgment.
type DriftConfidence struct {
	Level string  `json:"level"`
	Score float64 `json:"score,omitempty"`
	Basis string  `json:"basis,omitempty"`
}

// DriftFinding reports one contradiction between a doc and a spec.
type DriftFinding struct {
	SpecRef        string           `json:"spec_ref"`
	Artifact       string           `json:"artifact,omitempty"`
	Code           string           `json:"code"`
	Classification string           `json:"classification,omitempty"`
	DocRole        string           `json:"doc_role,omitempty"`
	SpecRole       string           `json:"spec_role,omitempty"`
	Message        string           `json:"message"`
	Rationale      string           `json:"rationale,omitempty"`
	Expected       string           `json:"expected,omitempty"`
	Observed       string           `json:"observed,omitempty"`
	Evidence       *DriftEvidence   `json:"evidence,omitempty"`
	Confidence     *DriftConfidence `json:"confidence,omitempty"`
}

// DriftItem reports one doc that drifts from accepted specs.
type DriftItem struct {
	DocRef    string         `json:"doc_ref"`
	Title     string         `json:"title"`
	Repo      string         `json:"repo,omitempty"`
	SourceRef string         `json:"source_ref"`
	SpecRefs  []string       `json:"spec_refs"`
	Findings  []DriftFinding `json:"findings"`
}

// DocDriftAssessment reports how one reviewed doc was judged, even when no deterministic drift was proven.
type DocDriftAssessment struct {
	DocRef     string           `json:"doc_ref"`
	Title      string           `json:"title"`
	Repo       string           `json:"repo,omitempty"`
	SourceRef  string           `json:"source_ref"`
	Status     string           `json:"status"`
	SpecRefs   []string         `json:"spec_refs,omitempty"`
	Rationale  string           `json:"rationale,omitempty"`
	Evidence   *DriftEvidence   `json:"evidence,omitempty"`
	Confidence *DriftConfidence `json:"confidence,omitempty"`
}

// DocRemediationEvidence separates the observed contradiction from the accepted spec evidence.
type DocRemediationEvidence struct {
	SpecSourceRef string `json:"spec_source_ref,omitempty"`
	SpecSection   string `json:"spec_section,omitempty"`
	SpecExcerpt   string `json:"spec_excerpt,omitempty"`
	DocSourceRef  string `json:"doc_source_ref,omitempty"`
	DocSection    string `json:"doc_section,omitempty"`
	DocExcerpt    string `json:"doc_excerpt,omitempty"`
	Expected      string `json:"expected,omitempty"`
	Observed      string `json:"observed,omitempty"`
	LinkReason    string `json:"link_reason,omitempty"`
}

// DocSuggestedEdit is one actionable update recommendation.
type DocSuggestedEdit struct {
	Action  string `json:"action"`
	Replace string `json:"replace,omitempty"`
	With    string `json:"with,omitempty"`
	Note    string `json:"note,omitempty"`
}

// DocRemediationSuggestion is one actionable guidance item derived from a drift finding.
type DocRemediationSuggestion struct {
	SpecRef          string                 `json:"spec_ref"`
	Code             string                 `json:"code"`
	Classification   string                 `json:"classification,omitempty"`
	Summary          string                 `json:"summary"`
	LinkReason       string                 `json:"link_reason,omitempty"`
	TargetSourceRef  string                 `json:"target_source_ref,omitempty"`
	TargetSection    string                 `json:"target_section,omitempty"`
	TargetExcerpt    string                 `json:"target_excerpt,omitempty"`
	SuggestedBullets []string               `json:"suggested_bullets,omitempty"`
	Evidence         DocRemediationEvidence `json:"evidence"`
	SuggestedEdit    DocSuggestedEdit       `json:"suggested_edit"`
}

// DocRemediationItem groups all remediation suggestions for one drifting doc.
type DocRemediationItem struct {
	DocRef      string                     `json:"doc_ref"`
	Title       string                     `json:"title"`
	Repo        string                     `json:"repo,omitempty"`
	SourceRef   string                     `json:"source_ref"`
	Suggestions []DocRemediationSuggestion `json:"suggestions"`
}

// DocRemediationResult is the structured remediation payload shared by doc-drift and review-spec.
type DocRemediationResult struct {
	Items []DocRemediationItem `json:"items"`
}

// DocDriftResult is the structured doc-drift response.
type DocDriftResult struct {
	Scope           DocDriftScope            `json:"scope"`
	ChangedFiles    []DriftChangedFile       `json:"changed_files,omitempty"`
	ImplicatedSpecs []DriftImplicatedSpec    `json:"implicated_specs,omitempty"`
	ImplicatedDocs  []DriftImplicatedDoc     `json:"implicated_docs,omitempty"`
	DriftItems      []DriftItem              `json:"drift_items"`
	Assessments     []DocDriftAssessment     `json:"assessments,omitempty"`
	SpecInferences  []SpecInference          `json:"spec_inferences,omitempty"`
	Remediation     *DocRemediationResult    `json:"remediation"`
	Runtime         *CommandRuntime          `json:"runtime,omitempty"`
	Warnings        []Warning                `json:"warnings,omitempty"`
	ContentTrust    *resultmeta.ContentTrust `json:"content_trust,omitempty"`
}

type normalizedClaims struct {
	Window          string
	Subject         string
	DefaultLimit    int
	HasDefaultLimit bool
	Overrides       *bool
}

type artifactMention struct {
	Artifact string
	Active   bool
	Aligned  bool
}

type artifactConstraint struct {
	Artifact string
	Kind     string
	Expected string
}

type alignedAssessmentCandidate struct {
	spec            *specDocument
	evidence        *DriftEvidence
	score           float64
	docMentionsSpec bool
	headingOverlap  bool
}

// CheckDocDrift detects contradictory docs within a target scope.
func CheckDocDrift(cfg *config.Config, request DocDriftRequest) (*DocDriftResult, error) {
	return CheckDocDriftContext(context.Background(), cfg, request)
}

// CheckDocDriftContext detects contradictory docs within a target scope.
func CheckDocDriftContext(ctx context.Context, cfg *config.Config, request DocDriftRequest) (*DocDriftResult, error) {
	if cfg == nil {
		return nil, fmt.Errorf("config is required")
	}

	scope, err := normalizeDocDriftScope(request)
	if err != nil {
		return nil, err
	}
	normalizedAtDate, err := temporal.NormalizeAtDate(request.AtDate)
	if err != nil {
		return nil, err
	}

	repo, err := openAnalysisRepositoryContext(ctx, cfg)
	if err != nil {
		return nil, err
	}
	defer repo.Close()
	repo.atDate = normalizedAtDate
	repo.minConfidence = strings.TrimSpace(request.MinConfidence)

	analyzer, err := newQualitativeAnalyzer(cfg.Runtime.Analysis)
	if err != nil {
		return nil, err
	}
	analyzer = qualitativeAnalyzerWithTimings(ctx, analyzer)
	analysisRuntime := newAnalysisRuntimeUsage(cfg.Runtime.Analysis)

	var (
		selectedDocs    map[string]docDocument
		specs           map[string]specDocument
		changedFiles    []DriftChangedFile
		implicatedSpecs []DriftImplicatedSpec
		implicatedDocs  []DriftImplicatedDoc
	)
	if scope.Mode == "diff" {
		selectedDocs, specs, changedFiles, implicatedSpecs, implicatedDocs, err = resolveDiffDocDriftContext(ctx, repo, cfg, request.DiffText)
		if err != nil {
			return nil, err
		}
	} else {
		selectedDocs, err = repo.loadDocs(scope.DocRefs)
		if err != nil {
			return nil, err
		}
		if len(scope.DocRefs) > 0 {
			for _, ref := range scope.DocRefs {
				if _, ok := selectedDocs[ref]; !ok {
					return nil, newDocRefNotFoundError(ref)
				}
			}
		}

		specRefs, err := repo.relevantDocDriftSpecRefs(selectedDocs)
		if err != nil {
			return nil, err
		}
		specs, err = repo.loadSelectedSpecs(specRefs)
		if err != nil {
			return nil, err
		}
	}

	result, err := buildDocDriftResult(ctx, analyzer, analysisRuntime, scope, selectedDocs, specs, repo.loadAllSpecs)
	if err != nil {
		return nil, err
	}
	result.ChangedFiles = changedFiles
	result.ImplicatedSpecs = implicatedSpecs
	result.ImplicatedDocs = implicatedDocs
	return result, nil
}

func buildDocDriftResult(ctx context.Context, analyzer qualitativeAnalyzer, analysisRuntime *RuntimeUsage, scope DocDriftScope, selectedDocs map[string]docDocument, specs map[string]specDocument, loadAllSpecs func() (map[string]specDocument, error)) (*DocDriftResult, error) {
	loader := newDocDriftSpecLoader(specs, loadAllSpecs)
	state, pending, err := collectDocDriftDeterministicResults(analyzer, selectedDocs, specs, loader)
	if err != nil {
		return nil, err
	}
	refined, err := refinePendingDocDriftResults(ctx, analyzer, analysisRuntime, pending)
	if err != nil {
		return nil, err
	}
	mergeRefinedDocDriftResults(&state, pending, refined, specs)
	relevantSpecRefs := uniqueStrings(state.relevantSpecRefs)

	var runtime *CommandRuntime
	if analysisRuntime != nil {
		runtime = &CommandRuntime{Analysis: analysisRuntime}
	}

	return &DocDriftResult{
		Scope:          scope,
		DriftItems:     state.driftItems,
		Assessments:    state.assessments,
		SpecInferences: buildSpecInferences(loader.inferenceSpecs(), relevantSpecRefs),
		Remediation: &DocRemediationResult{
			Items: state.remediationItems,
		},
		Runtime:      runtime,
		Warnings:     buildSpecInferenceWarnings("doc-drift analysis", state.warningSpecs...),
		ContentTrust: resultmeta.UntrustedWorkspaceText(),
	}, nil
}

type pendingDocDriftRefinement struct {
	ref         string
	doc         docDocument
	relevant    []specDocument
	item        *DriftItem
	remediation *DocRemediationItem
}

type refinedDocDriftResult struct {
	item        *DriftItem
	remediation *DocRemediationItem
}

type docDriftBuildState struct {
	driftItems       []DriftItem
	assessments      []DocDriftAssessment
	remediationItems []DocRemediationItem
	relevantSpecRefs []string
	warningSpecs     []specDocument
}

type docDriftSpecLoader struct {
	baseSpecs    map[string]specDocument
	loadAllSpecs func() (map[string]specDocument, error)
	allSpecs     map[string]specDocument
}

func newDocDriftSpecLoader(specs map[string]specDocument, loadAllSpecs func() (map[string]specDocument, error)) *docDriftSpecLoader {
	return &docDriftSpecLoader{
		baseSpecs:    specs,
		loadAllSpecs: loadAllSpecs,
	}
}

func (l *docDriftSpecLoader) ensureAllSpecs() (map[string]specDocument, error) {
	if l.allSpecs != nil || l.loadAllSpecs == nil {
		return l.allSpecs, nil
	}
	loaded, err := l.loadAllSpecs()
	if err != nil {
		return nil, err
	}
	l.allSpecs = loaded
	return l.allSpecs, nil
}

func (l *docDriftSpecLoader) inferenceSpecs() map[string]specDocument {
	if l.allSpecs != nil {
		return l.allSpecs
	}
	return l.baseSpecs
}

func newDocDriftBuildState(selectedDocCount, specCount int) docDriftBuildState {
	return docDriftBuildState{
		driftItems:       make([]DriftItem, 0, selectedDocCount),
		assessments:      make([]DocDriftAssessment, 0, selectedDocCount),
		remediationItems: make([]DocRemediationItem, 0, selectedDocCount),
		relevantSpecRefs: make([]string, 0, specCount),
		warningSpecs:     make([]specDocument, 0, specCount),
	}
}

func (s *docDriftBuildState) appendAssessment(assessment *DocDriftAssessment, specs map[string]specDocument) {
	if assessment == nil {
		return
	}
	s.assessments = append(s.assessments, *assessment)
	s.relevantSpecRefs = append(s.relevantSpecRefs, assessment.SpecRefs...)
	for _, specRef := range assessment.SpecRefs {
		if spec, ok := specs[specRef]; ok {
			s.warningSpecs = append(s.warningSpecs, spec)
		}
	}
}

func (s *docDriftBuildState) appendItem(item *DriftItem, remediation *DocRemediationItem, specs map[string]specDocument) {
	if item == nil {
		return
	}
	s.driftItems = append(s.driftItems, *item)
	if remediation != nil {
		s.remediationItems = append(s.remediationItems, *remediation)
	}
	for _, specRef := range item.SpecRefs {
		if spec, ok := specs[specRef]; ok {
			s.relevantSpecRefs = append(s.relevantSpecRefs, specRef)
			s.warningSpecs = append(s.warningSpecs, spec)
		}
	}
}

func collectDocDriftDeterministicResults(analyzer qualitativeAnalyzer, selectedDocs map[string]docDocument, specs map[string]specDocument, loader *docDriftSpecLoader) (docDriftBuildState, []pendingDocDriftRefinement, error) {
	state := newDocDriftBuildState(len(selectedDocs), len(specs))
	pending := make([]pendingDocDriftRefinement, 0, len(selectedDocs))

	for _, ref := range sortedDocRefs(selectedDocs) {
		doc := selectedDocs[ref]
		relevant := relevantAcceptedSpecs(doc, specs)
		if roleToleratesHistoricalDrift(doc) {
			state.appendAssessment(historicalDocAssessment(doc, relevant), specs)
			continue
		}

		item, remediation := driftAgainstAcceptedSpecs(doc, relevant)
		if item != nil && analyzer != nil {
			pending = append(pending, pendingDocDriftRefinement{
				ref:         ref,
				doc:         doc,
				relevant:    relevant,
				item:        item,
				remediation: remediation,
			})
			continue
		}

		if assessment := assessDocDrift(doc, relevant, item); assessment != nil {
			state.appendAssessment(assessment, specs)
		} else if item == nil {
			allSpecs, err := loader.ensureAllSpecs()
			if err != nil {
				return docDriftBuildState{}, nil, err
			}
			state.appendAssessment(possibleDriftAssessment(doc, allSpecs), allSpecs)
		}
		state.appendItem(item, remediation, specs)
	}

	return state, pending, nil
}

func refinePendingDocDriftResults(ctx context.Context, analyzer qualitativeAnalyzer, analysisRuntime *RuntimeUsage, pending []pendingDocDriftRefinement) ([]refinedDocDriftResult, error) {
	refined := make([]refinedDocDriftResult, len(pending))
	if len(pending) == 0 || analyzer == nil {
		return refined, nil
	}
	if analysisRuntime != nil {
		analysisRuntime.Used = true
	}

	var mu sync.Mutex
	g, gctx := errgroup.WithContext(ctx)
	g.SetLimit(adjudicationConcurrency)

	for i, pendingItem := range pending {
		i := i
		pendingItem := pendingItem
		g.Go(func() error {
			shortlist := pendingItem.relevant
			if len(shortlist) > docDriftRelevantSpecLimit {
				shortlist = shortlist[:docDriftRelevantSpecLimit]
			}
			relevantByRef := make(map[string]specDocument, len(shortlist))
			for _, spec := range shortlist {
				relevantByRef[spec.Record.Ref] = spec
			}
			item, remediation, err := analyzer.RefineDocDrift(gctx, pendingItem.doc, relevantByRef, *pendingItem.item, pendingItem.remediation)
			if err != nil {
				return err
			}
			mu.Lock()
			refined[i] = refinedDocDriftResult{item: item, remediation: remediation}
			mu.Unlock()
			return nil
		})
	}

	if err := g.Wait(); err != nil {
		return nil, err
	}
	return refined, nil
}

func mergeRefinedDocDriftResults(state *docDriftBuildState, pending []pendingDocDriftRefinement, refined []refinedDocDriftResult, specs map[string]specDocument) {
	for i, pendingItem := range pending {
		item := pendingItem.item
		remediation := pendingItem.remediation
		if refined[i].item != nil {
			item = refined[i].item
		}
		if refined[i].remediation != nil {
			remediation = refined[i].remediation
		}
		state.appendAssessment(assessDocDrift(pendingItem.doc, pendingItem.relevant, item), specs)
		state.appendItem(item, remediation, specs)
	}
}

func normalizeDocDriftScope(request DocDriftRequest) (DocDriftScope, error) {
	hasDocRef := stringsTrimSpace(request.DocRef) != ""
	docRefs := uniqueStrings(request.DocRefs)
	hasDocRefs := len(docRefs) > 0
	hasScope := stringsTrimSpace(request.Scope) != ""
	hasDiff := stringsTrimSpace(request.DiffText) != ""

	count := 0
	if hasDocRef {
		count++
	}
	if hasDocRefs {
		count++
	}
	if hasScope {
		count++
	}
	if hasDiff {
		count++
	}
	if count != 1 {
		return DocDriftScope{}, fmt.Errorf("exactly one of doc_ref, doc_refs, scope, or diff_text is required")
	}

	switch {
	case hasDocRef:
		return DocDriftScope{Mode: "doc_ref", DocRefs: []string{stringsTrimSpace(request.DocRef)}}, nil
	case hasDocRefs:
		return DocDriftScope{Mode: "doc_refs", DocRefs: docRefs}, nil
	case hasDiff:
		return DocDriftScope{Mode: "diff", DocRefs: nil}, nil
	default:
		if stringsTrimSpace(request.Scope) != "all" {
			return DocDriftScope{}, fmt.Errorf("scope %q is invalid", request.Scope)
		}
		return DocDriftScope{Mode: "all", DocRefs: nil}, nil
	}
}

func loadIndexedDocsContext(ctx context.Context, db *sql.DB, snapshot *stindex.Snapshot, refs []string) (map[string]docDocument, error) {
	rows, err := loadIndexedDocRowsContext(ctx, db, refs)
	if err != nil {
		return nil, err
	}

	docs := make(map[string]docDocument, len(rows))
	for _, row := range rows {
		docs[row.Ref] = docDocument{
			Record: model.DocRecord{
				Ref:        row.Ref,
				Kind:       model.ArtifactKindDoc,
				Title:      row.Title,
				SourceRef:  row.SourceRef,
				BodyFormat: model.BodyFormatMarkdown,
				Metadata:   row.Metadata,
			},
		}
	}
	if err := loadDocSectionsContext(ctx, snapshot, docs); err != nil {
		return nil, err
	}
	return docs, nil
}

func loadIndexedDocRowsContext(ctx context.Context, db *sql.DB, refs []string) ([]indexedArtifactRow, error) {
	var builder strings.Builder
	args := make([]any, 0, len(refs)+1)
	builder.WriteString(`
SELECT ref, title, '', '', source_ref
     , metadata_json
FROM artifacts
WHERE kind = ?`)
	args = append(args, model.ArtifactKindDoc)
	if len(refs) > 0 {
		builder.WriteString(" AND ref IN (")
		for i, ref := range refs {
			if i > 0 {
				builder.WriteString(", ")
			}
			builder.WriteString("?")
			args = append(args, ref)
		}
		builder.WriteString(")")
	}

	rows, err := db.QueryContext(ctx, builder.String(), args...)
	if err != nil {
		return nil, fmt.Errorf("query indexed docs: %w", err)
	}
	defer rows.Close()

	var result []indexedArtifactRow
	for rows.Next() {
		var row indexedArtifactRow
		var rawMetadata string
		if err := rows.Scan(&row.Ref, &row.Title, &row.Status, &row.Domain, &row.SourceRef, &rawMetadata); err != nil {
			return nil, fmt.Errorf("scan indexed doc: %w", err)
		}
		if strings.TrimSpace(rawMetadata) != "" {
			if err := json.Unmarshal([]byte(rawMetadata), &row.Metadata); err != nil {
				return nil, fmt.Errorf("parse indexed metadata for %s: %w", row.Ref, err)
			}
		}
		result = append(result, row)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate indexed docs: %w", err)
	}
	return result, nil
}

func loadDocSectionsContext(ctx context.Context, snapshot *stindex.Snapshot, docs map[string]docDocument) error {
	refs := sortedDocRefs(docs)
	if len(refs) == 0 {
		return nil
	}

	sections, err := snapshot.Sections(ctx, stindex.SectionQuery{
		Refs:              refs,
		Kinds:             []string{model.ArtifactKindDoc},
		IncludeEmbeddings: true,
	})
	if err != nil {
		return fmt.Errorf("query doc sections: %w", err)
	}

	for _, section := range sections {
		document, ok := docs[section.Ref]
		if !ok {
			continue
		}
		document.Sections = append(document.Sections, embeddedSection{
			Heading:   section.Heading,
			Content:   section.Content,
			Embedding: append([]float64(nil), section.Embedding...),
		})
		docs[section.Ref] = document
	}
	return nil
}

func sortedDocRefs(docs map[string]docDocument) []string {
	refs := make([]string, 0, len(docs))
	for ref := range docs {
		refs = append(refs, ref)
	}
	sort.Strings(refs)
	return refs
}

func driftAgainstAcceptedSpecs(doc docDocument, relevant []specDocument) (*DriftItem, *DocRemediationItem) {
	if len(relevant) == 0 {
		return nil, nil
	}

	docClaims := claimsFromText(joinDocumentText(doc.Sections))
	docArtifacts := artifactMentionsFromSections(doc.Sections)
	var (
		specRefs []string
		findings []DriftFinding
		byRef    = make(map[string]specDocument, len(relevant))
	)
	for _, spec := range relevant {
		byRef[spec.Record.Ref] = spec
		specFindings := contradictingFindings(docClaims, claimsFromText(joinDocumentText(spec.Sections)), spec.Record.Ref)
		specFindings = append(specFindings, artifactDriftFindings(docArtifacts, spec)...)
		if len(specFindings) == 0 {
			continue
		}
		specRefs = append(specRefs, spec.Record.Ref)
		findings = append(findings, specFindings...)
	}
	findings = uniqueDriftFindings(findings)
	if len(findings) == 0 {
		return nil, nil
	}
	for i := range findings {
		spec, ok := byRef[findings[i].SpecRef]
		if !ok {
			continue
		}
		findings[i] = enrichDriftFinding(doc, spec, findings[i])
	}

	item := &DriftItem{
		DocRef:    doc.Record.Ref,
		Title:     doc.Record.Title,
		Repo:      artifactRepoID(doc.Record.Metadata),
		SourceRef: doc.Record.SourceRef,
		SpecRefs:  uniqueStrings(specRefs),
		Findings:  findings,
	}
	return item, buildDocRemediationItem(doc, byRef, findings)
}

func enrichDriftFinding(doc docDocument, spec specDocument, finding DriftFinding) DriftFinding {
	finding.DocRole = sourceRoleFromMetadata(doc.Record.Metadata)
	finding.SpecRole = sourceRoleFromMetadata(spec.Record.Metadata)
	finding.Classification = classifyDriftFinding(finding.DocRole, finding.SpecRole)
	evidence, score := driftEvidence(doc, spec, finding)
	finding.Evidence = evidence
	finding.Rationale = rationaleForFinding(finding)
	finding.Confidence = confidenceForDriftFinding(finding, score)
	return finding
}

func assessDocDrift(doc docDocument, relevant []specDocument, item *DriftItem) *DocDriftAssessment {
	if item != nil {
		assessment := &DocDriftAssessment{
			DocRef:    item.DocRef,
			Title:     item.Title,
			Repo:      item.Repo,
			SourceRef: item.SourceRef,
			Status:    "drift",
			SpecRefs:  append([]string(nil), item.SpecRefs...),
		}
		if finding := topDriftFinding(item.Findings); finding != nil {
			assessment.Rationale = defaultString(stringsTrimSpace(finding.Rationale), finding.Message)
			assessment.Evidence = cloneDriftEvidence(finding.Evidence)
			assessment.Confidence = cloneDriftConfidence(finding.Confidence)
		}
		if assessment.Confidence == nil {
			assessment.Confidence = &DriftConfidence{
				Level: "medium",
				Basis: "deterministic drift findings were emitted for this doc",
			}
		}
		return assessment
	}
	if len(relevant) == 0 {
		return nil
	}
	candidate := bestAlignedAssessmentCandidateForDocs(doc, relevant)
	if !shouldEmitAlignedAssessment(candidate) {
		return nil
	}
	return &DocDriftAssessment{
		DocRef:     doc.Record.Ref,
		Title:      doc.Record.Title,
		Repo:       artifactRepoID(doc.Record.Metadata),
		SourceRef:  doc.Record.SourceRef,
		Status:     "aligned",
		SpecRefs:   []string{candidate.spec.Record.Ref},
		Rationale:  fmt.Sprintf("matched accepted spec %s and found no deterministic contradiction in the reviewed sections", candidate.spec.Record.Ref),
		Evidence:   candidate.evidence,
		Confidence: &DriftConfidence{Level: alignmentConfidenceLevel(candidate.score), Score: roundScore(candidate.score), Basis: "nearest accepted spec and doc sections agree semantically, but no explicit contradiction was detected"},
	}
}

func possibleDriftAssessment(doc docDocument, specs map[string]specDocument) *DocDriftAssessment {
	candidates := assessmentFallbackSpecs(doc, specs)
	if len(candidates) == 0 {
		return nil
	}
	bestSpec, evidence, score := bestAlignedAssessmentEvidence(doc, candidates)
	if bestSpec == nil || evidence == nil {
		return nil
	}
	return &DocDriftAssessment{
		DocRef:     doc.Record.Ref,
		Title:      doc.Record.Title,
		Repo:       artifactRepoID(doc.Record.Metadata),
		SourceRef:  doc.Record.SourceRef,
		Status:     "possible_drift",
		SpecRefs:   []string{bestSpec.Record.Ref},
		Rationale:  fmt.Sprintf("doc is semantically or lexically close to accepted spec %s, but the current deterministic doc-drift rules could not prove contradiction; inspect it manually", bestSpec.Record.Ref),
		Evidence:   evidence,
		Confidence: &DriftConfidence{Level: "low", Score: roundScore(score), Basis: "nearest accepted spec is suggestive, but this is not a deterministic contradiction"},
	}
}

func assessmentFallbackSpecs(doc docDocument, specs map[string]specDocument) []specDocument {
	type scoredSpec struct {
		spec  specDocument
		score float64
	}

	var (
		scored              []scoredSpec
		authoritativeScored []scoredSpec
	)
	for _, spec := range specs {
		if spec.Record.Status != model.StatusAccepted {
			continue
		}
		score := assessmentSimilarity(doc.Sections, spec.Sections)
		entry := scoredSpec{spec: spec, score: score}
		scored = append(scored, entry)
		if sourceRoleIsAuthoritative(spec.Record.Metadata) {
			authoritativeScored = append(authoritativeScored, entry)
		}
	}
	if len(authoritativeScored) > 0 {
		scored = authoritativeScored
	}
	sort.Slice(scored, func(i, j int) bool {
		switch {
		case scored[i].score != scored[j].score:
			return scored[i].score > scored[j].score
		default:
			return scored[i].spec.Record.Ref < scored[j].spec.Record.Ref
		}
	})
	if len(scored) == 0 {
		return nil
	}

	limit := minInt(len(scored), 2)
	result := make([]specDocument, 0, limit)
	for _, item := range scored[:limit] {
		result = append(result, item.spec)
	}
	return result
}

func buildDocRemediationItem(doc docDocument, specs map[string]specDocument, findings []DriftFinding) *DocRemediationItem {
	suggestions := make([]DocRemediationSuggestion, 0, len(findings))
	for _, finding := range findings {
		spec, ok := specs[finding.SpecRef]
		if !ok {
			continue
		}
		evidence := remediationEvidence(doc, spec, finding)
		suggestions = append(suggestions, DocRemediationSuggestion{
			SpecRef:          finding.SpecRef,
			Code:             finding.Code,
			Classification:   finding.Classification,
			Summary:          remediationSummaryForFinding(finding),
			LinkReason:       defaultString(stringsTrimSpace(evidence.LinkReason), defaultString(stringsTrimSpace(finding.Rationale), finding.Message)),
			TargetSourceRef:  evidence.DocSourceRef,
			TargetSection:    evidence.DocSection,
			TargetExcerpt:    evidence.DocExcerpt,
			SuggestedBullets: remediationSuggestedBullets(doc, spec, finding, evidence),
			Evidence:         evidence,
			SuggestedEdit:    suggestedEditForFinding(finding),
		})
	}
	if len(suggestions) == 0 {
		return nil
	}
	return &DocRemediationItem{
		DocRef:      doc.Record.Ref,
		Title:       doc.Record.Title,
		Repo:        artifactRepoID(doc.Record.Metadata),
		SourceRef:   doc.Record.SourceRef,
		Suggestions: suggestions,
	}
}

func relevantAcceptedSpecs(doc docDocument, specs map[string]specDocument) []specDocument {
	type scoredSpec struct {
		spec  specDocument
		score float64
	}
	docArtifacts := artifactMentionSet(doc.Sections)
	var (
		scored              []scoredSpec
		authoritativeScored []scoredSpec
	)
	for _, spec := range specs {
		if spec.Record.Status != model.StatusAccepted {
			continue
		}
		score := documentSimilarity(doc.Sections, spec.Sections)
		if hasArtifactConstraintOverlap(docArtifacts, spec) {
			score += 0.4
		}
		if score < docDriftSimilarityThreshold {
			continue
		}
		entry := scoredSpec{spec: spec, score: score}
		scored = append(scored, entry)
		if sourceRoleIsAuthoritative(spec.Record.Metadata) {
			authoritativeScored = append(authoritativeScored, entry)
		}
	}
	if len(authoritativeScored) > 0 {
		scored = authoritativeScored
	}
	sort.Slice(scored, func(i, j int) bool {
		switch {
		case scored[i].score != scored[j].score:
			return scored[i].score > scored[j].score
		default:
			return scored[i].spec.Record.Ref < scored[j].spec.Record.Ref
		}
	})

	result := make([]specDocument, 0, len(scored))
	for _, item := range scored {
		result = append(result, item.spec)
	}
	return result
}

func roleToleratesHistoricalDrift(doc docDocument) bool {
	return sourceRoleFromMetadata(doc.Record.Metadata) == config.SourceRoleHistorical
}

func historicalDocAssessment(doc docDocument, relevant []specDocument) *DocDriftAssessment {
	assessment := &DocDriftAssessment{
		DocRef:    doc.Record.Ref,
		Title:     doc.Record.Title,
		Repo:      artifactRepoID(doc.Record.Metadata),
		SourceRef: doc.Record.SourceRef,
		Status:    "aligned",
		Rationale: "doc source is marked historical, so historical terminology and superseded behavior are tolerated during drift checks",
		Confidence: &DriftConfidence{
			Level: "medium",
			Basis: "source role marks this document as historical context rather than current operational truth",
		},
	}
	if candidate := bestAlignedAssessmentCandidateForDocs(doc, relevant); shouldEmitAlignedAssessment(candidate) {
		assessment.SpecRefs = []string{candidate.spec.Record.Ref}
		assessment.Evidence = candidate.evidence
		assessment.Confidence.Score = roundScore(candidate.score)
	}
	return assessment
}

func sourceRoleFromMetadata(metadata map[string]string) string {
	if len(metadata) == 0 {
		return ""
	}
	return config.NormalizeSourceRole(metadata[sourceRoleMetadataKey])
}

func sourceRoleIsAuthoritative(metadata map[string]string) bool {
	switch sourceRoleFromMetadata(metadata) {
	case "":
		return true
	case config.SourceRoleCanonical, config.SourceRoleCurrentState, config.SourceRoleRuntimeAuth:
		return true
	default:
		return false
	}
}

func classifyDriftFinding(docRole, specRole string) string {
	docRole = config.NormalizeSourceRole(docRole)
	specRole = config.NormalizeSourceRole(specRole)
	if docRole == "" && specRole == "" {
		return driftClassificationSemantic
	}
	if docRole != "" && specRole != "" && docRole != specRole {
		return driftClassificationRole
	}
	switch docRole {
	case config.SourceRolePlanning, config.SourceRoleGenerated, config.SourceRoleMirror:
		return driftClassificationRole
	default:
		return driftClassificationSemantic
	}
}

func humanizeSourceRole(role string) string {
	switch config.NormalizeSourceRole(role) {
	case config.SourceRoleCanonical:
		return "canonical"
	case config.SourceRoleCurrentState:
		return "current-state"
	case config.SourceRoleRuntimeAuth:
		return "runtime-authoritative"
	case config.SourceRolePlanning:
		return "planning"
	case config.SourceRoleHistorical:
		return "historical"
	case config.SourceRoleGenerated:
		return "generated"
	case config.SourceRoleMirror:
		return "mirror"
	default:
		return ""
	}
}

func joinDocumentText(sections []embeddedSection) string {
	parts := make([]string, 0, len(sections))
	for _, section := range sections {
		if trimmed := strings.TrimSpace(section.Content); trimmed != "" {
			parts = append(parts, trimmed)
		}
	}
	return strings.Join(parts, "\n")
}

func claimsFromText(text string) normalizedClaims {
	claims := normalizedClaims{}
	lower := strings.ToLower(text)

	switch {
	case strings.Contains(lower, "sliding-window"):
		claims.Window = "sliding-window"
	case strings.Contains(lower, "fixed-window"):
		claims.Window = "fixed-window"
	}

	switch {
	case strings.Contains(lower, "per tenant"), strings.Contains(lower, "tenant-scoped"), strings.Contains(lower, "tenant-specific"):
		claims.Subject = "tenant"
	case strings.Contains(lower, "per api key"), strings.Contains(lower, "api key"):
		claims.Subject = "api_key"
	}

	if matches := requestsPerMinutePattern.FindStringSubmatch(lower); len(matches) == 2 {
		if value, err := strconv.Atoi(matches[1]); err == nil {
			claims.DefaultLimit = value
			claims.HasDefaultLimit = true
		}
	}

	switch {
	case strings.Contains(lower, "tenant-specific overrides are not supported"),
		strings.Contains(lower, "all tenants share the same rate-limit configuration"):
		value := false
		claims.Overrides = &value
	case strings.Contains(lower, "tenant-specific overrides through configuration"),
		strings.Contains(lower, "tenant override"),
		strings.Contains(lower, "tenant overrides"):
		value := true
		claims.Overrides = &value
	}

	return claims
}

func contradictingFindings(docClaims, specClaims normalizedClaims, specRef string) []DriftFinding {
	var findings []DriftFinding
	if docClaims.Window != "" && specClaims.Window != "" && docClaims.Window != specClaims.Window {
		findings = append(findings, DriftFinding{
			SpecRef:  specRef,
			Code:     "window_mismatch",
			Message:  "document describes a different rate-limiter window",
			Expected: specClaims.Window,
			Observed: docClaims.Window,
		})
	}
	if docClaims.Subject != "" && specClaims.Subject != "" && docClaims.Subject != specClaims.Subject {
		findings = append(findings, DriftFinding{
			SpecRef:  specRef,
			Code:     "subject_mismatch",
			Message:  "document targets a different rate-limit subject",
			Expected: specClaims.Subject,
			Observed: docClaims.Subject,
		})
	}
	if docClaims.HasDefaultLimit && specClaims.HasDefaultLimit && docClaims.DefaultLimit != specClaims.DefaultLimit {
		findings = append(findings, DriftFinding{
			SpecRef:  specRef,
			Code:     "default_limit_mismatch",
			Message:  "document reports a different default limit",
			Expected: strconv.Itoa(specClaims.DefaultLimit),
			Observed: strconv.Itoa(docClaims.DefaultLimit),
		})
	}
	if docClaims.Overrides != nil && specClaims.Overrides != nil && *docClaims.Overrides != *specClaims.Overrides {
		findings = append(findings, DriftFinding{
			SpecRef:  specRef,
			Code:     "override_support_mismatch",
			Message:  "document disagrees on tenant override support",
			Expected: strconv.FormatBool(*specClaims.Overrides),
			Observed: strconv.FormatBool(*docClaims.Overrides),
		})
	}
	return findings
}

func artifactDriftFindings(docArtifacts map[string][]artifactMention, spec specDocument) []DriftFinding {
	constraints := artifactConstraintsFromSections(spec.Sections)
	if len(constraints) == 0 || len(docArtifacts) == 0 {
		return nil
	}

	findings := make([]DriftFinding, 0, len(constraints))
	for _, constraint := range constraints {
		mentions := docArtifacts[constraint.Artifact]
		if len(mentions) == 0 {
			continue
		}
		for _, mention := range mentions {
			if mention.Aligned {
				continue
			}

			code := "artifact_contract_mismatch"
			message := fmt.Sprintf("document still presents `%s` as part of the active runtime contract", constraint.Artifact)
			observed := "documented as active runtime state"
			if constraint.Kind == "runtime_input" && mention.Active {
				code = "artifact_runtime_input_mismatch"
				message = fmt.Sprintf("document still treats `%s` as canonical runtime input", constraint.Artifact)
				observed = "documented as an active runtime input"
			}

			findings = append(findings, DriftFinding{
				SpecRef:  spec.Record.Ref,
				Artifact: constraint.Artifact,
				Code:     code,
				Message:  message,
				Expected: constraint.Expected,
				Observed: observed,
			})
			break
		}
	}
	return findings
}

func artifactMentionSet(sections []embeddedSection) map[string]struct{} {
	mentions := artifactMentionsFromSections(sections)
	result := make(map[string]struct{}, len(mentions))
	for artifact := range mentions {
		result[artifact] = struct{}{}
	}
	return result
}

func artifactMentionsFromSections(sections []embeddedSection) map[string][]artifactMention {
	mentions := map[string][]artifactMention{}
	for _, section := range sections {
		for _, line := range sectionContentLines(section.Content) {
			artifacts := artifactRefsFromText(line)
			if len(artifacts) == 0 {
				continue
			}
			lower := strings.ToLower(line)
			active := containsAny(
				lower,
				" read ", " reads ", " load ", " loads ",
				" write ", " writes ", " uses ", " use ",
				" cache", " cached", " storing ", " stored ",
				" refresh", " refreshes ", " startup", " start ",
			)
			aligned := containsAny(
				lower,
				"optional", "derived", "historical", "history", "archive",
				"legacy", "not part of", "not required", "must not",
				"implementation detail", "safe to discard",
			)
			for _, artifact := range artifacts {
				mentions[artifact] = append(mentions[artifact], artifactMention{
					Artifact: artifact,
					Active:   active,
					Aligned:  aligned,
				})
			}
		}
	}
	return mentions
}

func hasArtifactConstraintOverlap(docArtifacts map[string]struct{}, spec specDocument) bool {
	if len(docArtifacts) == 0 {
		return false
	}
	for _, constraint := range artifactConstraintsFromSections(spec.Sections) {
		if _, ok := docArtifacts[constraint.Artifact]; ok {
			return true
		}
	}
	return false
}

func artifactConstraintsFromSections(sections []embeddedSection) []artifactConstraint {
	constraints := map[string]artifactConstraint{}
	for _, section := range sections {
		for _, line := range sectionContentLines(section.Content) {
			artifacts := artifactRefsFromText(line)
			if len(artifacts) == 0 {
				continue
			}
			for _, artifact := range artifacts {
				kind, expected, ok := classifyArtifactConstraint(line, artifact)
				if !ok {
					continue
				}
				next := artifactConstraint{
					Artifact: artifact,
					Kind:     kind,
					Expected: expected,
				}
				current, exists := constraints[artifact]
				if !exists || artifactConstraintPriority(next.Kind) > artifactConstraintPriority(current.Kind) {
					constraints[artifact] = next
				}
			}
		}
	}

	artifacts := make([]string, 0, len(constraints))
	for artifact := range constraints {
		artifacts = append(artifacts, artifact)
	}
	sort.Strings(artifacts)

	result := make([]artifactConstraint, 0, len(artifacts))
	for _, artifact := range artifacts {
		result = append(result, constraints[artifact])
	}
	return result
}

func classifyArtifactConstraint(line, artifact string) (string, string, bool) {
	lower := strings.ToLower(line)
	artifact = strings.ToLower(artifact)
	local := lower
	runtimeLocal := lower
	if idx := strings.Index(lower, artifact); idx >= 0 {
		start := idx
		if start > 96 {
			start -= 96
		} else {
			start = 0
		}
		end := idx + len(artifact) + 128
		if end > len(lower) {
			end = len(lower)
		}
		local = lower[start:end]

		runtimeStart := idx
		if runtimeStart > 48 {
			runtimeStart -= 48
		} else {
			runtimeStart = 0
		}
		runtimeEnd := idx + len(artifact) + 32
		if runtimeEnd > len(lower) {
			runtimeEnd = len(lower)
		}
		runtimeLocal = lower[runtimeStart:runtimeEnd]
	}

	switch {
	case containsAny(
		runtimeLocal,
		"must not read", "must not load", "must not parse",
		"must not reparse", "must not treat",
	):
		return "runtime_input", "not a canonical runtime input", true
	case containsAny(
		local,
		artifact+"` is not a required artifact",
		artifact+" is not a required artifact",
		artifact+"` is not part of the accepted runtime contract",
		artifact+" is not part of the accepted runtime contract",
		artifact+"` is not part of the persisted runtime contract",
		artifact+" is not part of the persisted runtime contract",
	):
		return "contract", "not part of the accepted runtime contract", true
	case containsAny(
		lower,
		"legacy derived files",
	) && containsAny(
		lower,
		"not part of the accepted runtime contract",
		"not part of the persisted runtime contract",
	):
		return "contract", "not part of the accepted runtime contract", true
	default:
		return "", "", false
	}
}

func artifactConstraintPriority(kind string) int {
	switch kind {
	case "runtime_input":
		return 2
	case "contract":
		return 1
	default:
		return 0
	}
}

func uniqueDriftFindings(findings []DriftFinding) []DriftFinding {
	seen := map[string]struct{}{}
	result := make([]DriftFinding, 0, len(findings))
	for _, finding := range findings {
		key := strings.Join([]string{
			finding.SpecRef,
			finding.Artifact,
			finding.Code,
			finding.Message,
			finding.Expected,
			finding.Observed,
		}, "\x00")
		if _, ok := seen[key]; ok {
			continue
		}
		seen[key] = struct{}{}
		result = append(result, finding)
	}
	return result
}

func remediationSummaryForFinding(finding DriftFinding) string {
	switch finding.Code {
	case "window_mismatch":
		return "replace the stale limiter-window wording with the accepted window model"
	case "subject_mismatch":
		return "update the subject wording so the doc describes tenant-scoped limits"
	case "default_limit_mismatch":
		return "update the documented default rate limit to the accepted value"
	case "override_support_mismatch":
		return "replace the stale override-support statement with the accepted configuration behavior"
	case "artifact_runtime_input_mismatch":
		if finding.Artifact != "" {
			return fmt.Sprintf("rewrite the `%s` guidance so the doc stops treating it as canonical runtime input", finding.Artifact)
		}
		return "rewrite the stale artifact guidance so the doc stops treating it as canonical runtime input"
	case "artifact_contract_mismatch":
		if finding.Artifact != "" {
			return fmt.Sprintf("remove or qualify the stale `%s` reference so it is no longer presented as active runtime state", finding.Artifact)
		}
		return "remove or qualify the stale artifact reference so it is no longer presented as active runtime state"
	default:
		return finding.Message
	}
}

func remediationEvidence(doc docDocument, spec specDocument, finding DriftFinding) DocRemediationEvidence {
	evidence, _ := driftEvidence(doc, spec, finding)
	if evidence == nil {
		return DocRemediationEvidence{
			SpecSourceRef: spec.Record.SourceRef,
			DocSourceRef:  doc.Record.SourceRef,
			Expected:      humanizedDriftValue(finding.Code, finding.Expected),
			Observed:      humanizedDriftValue(finding.Code, finding.Observed),
			LinkReason:    defaultString(stringsTrimSpace(finding.Rationale), finding.Message),
		}
	}
	return DocRemediationEvidence{
		SpecSourceRef: evidence.SpecSourceRef,
		SpecSection:   evidence.SpecSection,
		SpecExcerpt:   evidence.SpecExcerpt,
		DocSourceRef:  evidence.DocSourceRef,
		DocSection:    evidence.DocSection,
		DocExcerpt:    evidence.DocExcerpt,
		Expected:      humanizedDriftValue(finding.Code, finding.Expected),
		Observed:      humanizedDriftValue(finding.Code, finding.Observed),
		LinkReason:    evidence.LinkReason,
	}
}

func remediationSuggestedBullets(doc docDocument, spec specDocument, finding DriftFinding, evidence DocRemediationEvidence) []string {
	bullets := make([]string, 0, 3)
	targetSection := defaultString(stringsTrimSpace(evidence.DocSection), "(body)")
	specSection := defaultString(stringsTrimSpace(evidence.SpecSection), "(body)")
	bullets = append(bullets, fmt.Sprintf("Review %s in %s against %s / %s before editing nearby guidance.", targetSection, doc.Record.Ref, spec.Record.Ref, specSection))
	switch finding.Code {
	case "window_mismatch", "subject_mismatch", "default_limit_mismatch", "override_support_mismatch":
		if observed := humanizedDriftValue(finding.Code, finding.Observed); observed != "" {
			if expected := humanizedDriftValue(finding.Code, finding.Expected); expected != "" {
				bullets = append(bullets, fmt.Sprintf("Replace the stale claim %q with the accepted value %q.", observed, expected))
			}
		}
	case "artifact_runtime_input_mismatch":
		if finding.Artifact != "" {
			bullets = append(bullets, fmt.Sprintf("Rewrite the `%s` paragraph so it is described as derived output rather than canonical runtime input.", finding.Artifact))
		}
	case "artifact_contract_mismatch":
		if finding.Artifact != "" {
			bullets = append(bullets, fmt.Sprintf("Remove or qualify `%s` so the doc no longer presents it as active runtime state.", finding.Artifact))
		}
	}
	if evidence.SpecExcerpt != "" {
		bullets = append(bullets, "Anchor the replacement text on the accepted spec excerpt instead of paraphrasing from memory.")
	}
	return normalizeStringList(bullets, 4)
}

func suggestedEditForFinding(finding DriftFinding) DocSuggestedEdit {
	switch finding.Code {
	case "window_mismatch":
		return DocSuggestedEdit{
			Action:  "replace_claim",
			Replace: humanizedDriftValue(finding.Code, finding.Observed),
			With:    humanizedDriftValue(finding.Code, finding.Expected),
			Note:    "Update the limiter-window description to match the accepted design.",
		}
	case "subject_mismatch":
		return DocSuggestedEdit{
			Action:  "replace_claim",
			Replace: humanizedDriftValue(finding.Code, finding.Observed),
			With:    humanizedDriftValue(finding.Code, finding.Expected),
			Note:    "Describe rate limits in terms of tenants, not API keys.",
		}
	case "default_limit_mismatch":
		return DocSuggestedEdit{
			Action:  "replace_claim",
			Replace: humanizedDriftValue(finding.Code, finding.Observed),
			With:    humanizedDriftValue(finding.Code, finding.Expected),
			Note:    "Bring the documented default limit back in line with the accepted spec.",
		}
	case "override_support_mismatch":
		return DocSuggestedEdit{
			Action:  "replace_claim",
			Replace: humanizedDriftValue(finding.Code, finding.Observed),
			With:    humanizedDriftValue(finding.Code, finding.Expected),
			Note:    "Document the accepted override behavior instead of the stale configuration guidance.",
		}
	case "artifact_runtime_input_mismatch":
		note := "Rewrite the section so the artifact is treated as derived output rather than canonical runtime input."
		if finding.Artifact != "" {
			note = fmt.Sprintf("Rewrite the `%s` references so the section treats it as derived output rather than canonical runtime input.", finding.Artifact)
		}
		return DocSuggestedEdit{
			Action: "update_section",
			Note:   note,
		}
	case "artifact_contract_mismatch":
		note := "Rewrite the section so the artifact is described as derived, optional, or historical rather than active runtime state."
		if finding.Artifact != "" {
			note = fmt.Sprintf("Rewrite the `%s` references so the section does not present it as active runtime state.", finding.Artifact)
		}
		return DocSuggestedEdit{
			Action: "update_section",
			Note:   note,
		}
	default:
		return DocSuggestedEdit{
			Action: "update_section",
			Note:   finding.Message,
		}
	}
}

func humanizedDriftValue(code, value string) string {
	switch code {
	case "window_mismatch":
		switch value {
		case "sliding-window":
			return "sliding-window rate limiter"
		case "fixed-window":
			return "fixed-window rate limiter"
		}
	case "subject_mismatch":
		switch value {
		case "tenant":
			return "tenant-scoped limits"
		case "api_key":
			return "API-key-scoped limits"
		}
	case "default_limit_mismatch":
		if value != "" {
			return value + " requests per minute"
		}
	case "override_support_mismatch":
		switch value {
		case "true":
			return "tenant-specific overrides are supported through configuration"
		case "false":
			return "tenant-specific overrides are not supported"
		}
	}
	return value
}

func evidenceKeywordsForFinding(finding DriftFinding) []string {
	switch finding.Code {
	case "window_mismatch":
		return []string{"window", "sliding-window", "fixed-window", "sliding window", "fixed window"}
	case "subject_mismatch":
		return []string{"tenant", "api key", "tenant-scoped", "api-key"}
	case "default_limit_mismatch":
		return []string{"requests per minute", finding.Expected, finding.Observed}
	case "override_support_mismatch":
		return []string{"override", "overrides", "configuration"}
	case "artifact_runtime_input_mismatch", "artifact_contract_mismatch":
		if finding.Artifact != "" {
			return []string{finding.Artifact}
		}
		return []string{finding.Expected, finding.Observed}
	default:
		return []string{finding.Expected, finding.Observed}
	}
}

func artifactRefsFromText(text string) []string {
	raw := artifactReferencePattern.FindAllString(text, -1)
	if len(raw) == 0 {
		return nil
	}
	seen := map[string]struct{}{}
	artifacts := make([]string, 0, len(raw))
	for _, match := range raw {
		artifact := strings.ToLower(strings.TrimSpace(match))
		if artifact == "" {
			continue
		}
		if _, ok := seen[artifact]; ok {
			continue
		}
		seen[artifact] = struct{}{}
		artifacts = append(artifacts, artifact)
	}
	sort.Strings(artifacts)
	return artifacts
}

func sectionContentLines(content string) []string {
	lines := strings.Split(content, "\n")
	result := make([]string, 0, len(lines))
	for _, line := range lines {
		trimmed := stringsTrimSpace(strings.TrimPrefix(line, "- "))
		if trimmed == "" {
			continue
		}
		result = append(result, trimmed)
	}
	return result
}

func containsAny(text string, values ...string) bool {
	for _, value := range values {
		if value != "" && strings.Contains(text, value) {
			return true
		}
	}
	return false
}

func sectionExcerptForKeywords(section embeddedSection, keywords []string) (string, bool) {
	lines := strings.Split(section.Content, "\n")
	for _, line := range lines {
		trimmed := stringsTrimSpace(strings.TrimPrefix(line, "- "))
		if trimmed == "" {
			continue
		}
		lower := strings.ToLower(trimmed)
		for _, keyword := range keywords {
			keyword = strings.ToLower(stringsTrimSpace(keyword))
			if keyword == "" {
				continue
			}
			if strings.Contains(lower, keyword) {
				return trimmed, true
			}
		}
	}
	return "", false
}

func stringsTrimSpace(value string) string {
	return strings.TrimSpace(value)
}

func stringsHasPrefix(value, prefix string) bool {
	return strings.HasPrefix(value, prefix)
}

func rationaleForFinding(finding DriftFinding) string {
	base := ""
	switch finding.Code {
	case "window_mismatch":
		base = fmt.Sprintf("accepted spec expects %s, but the doc still describes %s", humanizedDriftValue(finding.Code, finding.Expected), humanizedDriftValue(finding.Code, finding.Observed))
	case "subject_mismatch":
		base = fmt.Sprintf("accepted spec expects %s, but the doc still targets %s", humanizedDriftValue(finding.Code, finding.Expected), humanizedDriftValue(finding.Code, finding.Observed))
	case "default_limit_mismatch":
		base = fmt.Sprintf("accepted spec sets %s, but the doc still states %s", humanizedDriftValue(finding.Code, finding.Expected), humanizedDriftValue(finding.Code, finding.Observed))
	case "override_support_mismatch":
		base = fmt.Sprintf("accepted spec says %s, but the doc still says %s", humanizedDriftValue(finding.Code, finding.Expected), humanizedDriftValue(finding.Code, finding.Observed))
	case "artifact_runtime_input_mismatch":
		if finding.Artifact != "" {
			base = fmt.Sprintf("accepted spec says `%s` is not a canonical runtime input, but the doc still presents it as active startup input", finding.Artifact)
		}
	case "artifact_contract_mismatch":
		if finding.Artifact != "" {
			base = fmt.Sprintf("accepted spec says `%s` is not part of the active runtime contract, but the doc still presents it as active runtime state", finding.Artifact)
		}
	}
	if base == "" {
		base = finding.Message
	}
	if finding.Classification != driftClassificationRole {
		return base
	}
	docRole := humanizeSourceRole(finding.DocRole)
	specRole := humanizeSourceRole(finding.SpecRole)
	switch {
	case docRole != "" && specRole != "":
		return fmt.Sprintf("%s (%s source contradicts %s source)", base, docRole, specRole)
	case docRole != "":
		return fmt.Sprintf("%s (%s source is not the active operational authority)", base, docRole)
	case specRole != "":
		return fmt.Sprintf("%s (%s source takes precedence here)", base, specRole)
	default:
		return base
	}
}

func confidenceForDriftFinding(finding DriftFinding, score float64) *DriftConfidence {
	level := "medium"
	basis := "finding is backed by deterministic evidence excerpts from the doc and accepted spec"
	if finding.Evidence != nil && finding.Evidence.DocExcerpt != "" && finding.Evidence.SpecExcerpt != "" {
		level = "high"
		if score > 0 {
			basis = "finding is backed by explicit doc/spec excerpts that also align semantically"
		}
	} else if finding.Evidence == nil || (finding.Evidence.DocExcerpt == "" && finding.Evidence.SpecExcerpt == "") {
		level = "low"
		basis = "finding is deterministic, but the supporting doc/spec excerpts could not be localized precisely"
	}
	confidence := &DriftConfidence{
		Level: level,
		Basis: basis,
	}
	if score > 0 {
		confidence.Score = roundScore(score)
	}
	return confidence
}

func driftEvidence(doc docDocument, spec specDocument, finding DriftFinding) (*DriftEvidence, float64) {
	keywords := evidenceKeywordsForFinding(finding)
	docSection := bestSectionForKeywords(doc.Sections, keywords)
	specSection := bestSectionForKeywords(spec.Sections, keywords)
	if docSection == nil && specSection == nil {
		return nil, 0
	}

	score := 0.0
	if docSection != nil && specSection != nil {
		score = cosineSimilarity(docSection.Embedding, specSection.Embedding)
	}

	evidence := &DriftEvidence{
		SpecRef:       spec.Record.Ref,
		SpecTitle:     spec.Record.Title,
		SpecSourceRef: spec.Record.SourceRef,
		DocSourceRef:  doc.Record.SourceRef,
		LinkReason:    driftEvidenceLinkReason(finding, score, docSection != nil, specSection != nil),
	}
	if specSection != nil {
		evidence.SpecSection = defaultString(stringsTrimSpace(specSection.Heading), "(body)")
		evidence.SpecExcerpt = defaultString(sectionExcerpt(*specSection), stringsTrimSpace(spec.Record.Title))
	}
	if docSection != nil {
		evidence.DocSection = defaultString(stringsTrimSpace(docSection.Heading), "(body)")
		evidence.DocExcerpt = sectionExcerpt(*docSection)
	}
	return evidence, score
}

func driftEvidenceLinkReason(finding DriftFinding, score float64, hasDocSection, hasSpecSection bool) string {
	switch {
	case hasDocSection && hasSpecSection && score > 0:
		return fmt.Sprintf("localized the strongest doc/spec evidence pair for %s using deterministic keywords (score %.3f)", finding.Code, roundScore(score))
	case hasDocSection && hasSpecSection:
		return fmt.Sprintf("localized matching doc/spec sections for %s using deterministic keywords", finding.Code)
	case hasSpecSection:
		return fmt.Sprintf("localized the accepted spec section for %s and mapped the contradiction back to the reviewed doc", finding.Code)
	case hasDocSection:
		return fmt.Sprintf("localized the reviewed doc section for %s and paired it with the accepted spec finding", finding.Code)
	default:
		return ""
	}
}

func bestSectionForKeywords(sections []embeddedSection, keywords []string) *embeddedSection {
	for _, section := range sections {
		if _, ok := sectionExcerptForKeywords(section, keywords); ok {
			candidate := section
			return &candidate
		}
	}
	if len(sections) == 0 {
		return nil
	}

	var (
		best      embeddedSection
		bestScore float64
		found     bool
	)
	for _, section := range sections {
		excerpt := sectionExcerpt(section)
		if excerpt == "" {
			continue
		}
		score := keywordDensity(excerpt, keywords) + keywordDensity(section.Heading, keywords)
		if !found || score > bestScore {
			best = section
			bestScore = score
			found = true
		}
	}
	if !found {
		return nil
	}
	return &best
}

func keywordDensity(text string, keywords []string) float64 {
	if stringsTrimSpace(text) == "" || len(keywords) == 0 {
		return 0
	}
	lower := strings.ToLower(text)
	var score float64
	for _, keyword := range keywords {
		keyword = strings.ToLower(stringsTrimSpace(keyword))
		if keyword != "" && strings.Contains(lower, keyword) {
			score++
		}
	}
	return score
}

func bestAlignedAssessmentEvidence(doc docDocument, relevant []specDocument) (*specDocument, *DriftEvidence, float64) {
	candidate := bestAlignedAssessmentCandidateForDocs(doc, relevant)
	if candidate == nil {
		return nil, nil, 0
	}
	return candidate.spec, candidate.evidence, candidate.score
}

func bestAlignedAssessmentCandidateForDocs(doc docDocument, relevant []specDocument) *alignedAssessmentCandidate {
	docText := strings.ToLower(joinDocumentText(doc.Sections))
	var best *alignedAssessmentCandidate
	for i := range relevant {
		spec := &relevant[i]
		for j := range doc.Sections {
			docSection := &doc.Sections[j]
			for k := range spec.Sections {
				specSection := &spec.Sections[k]
				score := sectionAssessmentScore(*docSection, *specSection)
				if best != nil && score <= best.score {
					continue
				}
				best = &alignedAssessmentCandidate{
					spec: spec,
					evidence: &DriftEvidence{
						SpecRef:       spec.Record.Ref,
						SpecTitle:     spec.Record.Title,
						SpecSourceRef: spec.Record.SourceRef,
						SpecSection:   defaultString(stringsTrimSpace(specSection.Heading), "(body)"),
						SpecExcerpt:   defaultString(sectionExcerpt(*specSection), stringsTrimSpace(spec.Record.Title)),
						DocSourceRef:  doc.Record.SourceRef,
						DocSection:    defaultString(stringsTrimSpace(docSection.Heading), "(body)"),
						DocExcerpt:    sectionExcerpt(*docSection),
						LinkReason:    fmt.Sprintf("highest section-level alignment between %s and %s (score %.3f)", spec.Record.Ref, doc.Record.Ref, roundScore(score)),
					},
					score:           score,
					docMentionsSpec: strings.Contains(docText, strings.ToLower(spec.Record.Ref)),
					headingOverlap:  lexicalOverlapScore(docSection.Heading, specSection.Heading) >= 0.8,
				}
			}
		}
	}
	return best
}

func shouldEmitAlignedAssessment(candidate *alignedAssessmentCandidate) bool {
	if candidate == nil {
		return false
	}
	if candidate.score < 0.7 {
		return false
	}
	return candidate.docMentionsSpec || candidate.headingOverlap
}

func alignmentConfidenceLevel(score float64) string {
	switch {
	case score >= 0.82:
		return "high"
	case score >= 0.65:
		return "medium"
	default:
		return "low"
	}
}

func topDriftFinding(findings []DriftFinding) *DriftFinding {
	if len(findings) == 0 {
		return nil
	}
	bestIndex := 0
	for i := 1; i < len(findings); i++ {
		if compareDriftFindings(findings[i], findings[bestIndex]) < 0 {
			bestIndex = i
		}
	}
	return &findings[bestIndex]
}

func compareDriftFindings(left, right DriftFinding) int {
	leftRank := driftConfidenceRank(left.Confidence)
	rightRank := driftConfidenceRank(right.Confidence)
	switch {
	case leftRank != rightRank:
		return rightRank - leftRank
	case len(left.Rationale) != len(right.Rationale):
		if len(left.Rationale) > len(right.Rationale) {
			return -1
		}
		return 1
	case left.Code < right.Code:
		return -1
	case left.Code > right.Code:
		return 1
	default:
		return 0
	}
}

func driftConfidenceRank(confidence *DriftConfidence) int {
	if confidence == nil {
		return 0
	}
	switch confidence.Level {
	case "high":
		return 3
	case "medium":
		return 2
	case "low":
		return 1
	default:
		return 0
	}
}

func cloneDriftEvidence(evidence *DriftEvidence) *DriftEvidence {
	if evidence == nil {
		return nil
	}
	clone := *evidence
	return &clone
}

func cloneDriftConfidence(confidence *DriftConfidence) *DriftConfidence {
	if confidence == nil {
		return nil
	}
	clone := *confidence
	return &clone
}

func assessmentSimilarity(left, right []embeddedSection) float64 {
	if len(left) == 0 || len(right) == 0 {
		return 0
	}

	best := 0.0
	for _, leftSection := range left {
		for _, rightSection := range right {
			score := sectionAssessmentScore(leftSection, rightSection)
			if score > best {
				best = score
			}
		}
	}
	return best
}

func sectionAssessmentScore(left, right embeddedSection) float64 {
	semantic := cosineSimilarity(left.Embedding, right.Embedding)
	lexical := lexicalOverlapScore(
		textForEmbedding("", left.Heading, left.Content),
		textForEmbedding("", right.Heading, right.Content),
	)
	if semantic == 0 {
		return lexical
	}
	if lexical == 0 {
		return semantic
	}
	return (semantic * 0.8) + (lexical * 0.2)
}

func lexicalOverlapScore(left, right string) float64 {
	leftTokens := normalizedLexicalTokens(left)
	rightTokens := normalizedLexicalTokens(right)
	if len(leftTokens) == 0 || len(rightTokens) == 0 {
		return 0
	}
	shared := sharedStrings(leftTokens, rightTokens)
	if len(shared) == 0 {
		return 0
	}
	return float64(len(shared)) / float64(minInt(len(leftTokens), len(rightTokens)))
}

func normalizedLexicalTokens(text string) []string {
	var builder strings.Builder
	builder.Grow(len(text))
	for _, r := range strings.ToLower(text) {
		if unicode.IsLetter(r) || unicode.IsDigit(r) {
			builder.WriteRune(r)
			continue
		}
		builder.WriteByte(' ')
	}
	return uniqueStrings(strings.Fields(builder.String()))
}
