package optimizer

import "fmt"

// debugDiff produces annotated output showing original vs optimized code.
// Lines that were removed are shown with "[removed]" annotation.
func debugDiff(original, optimized []asmLine) []asmLine {
	// Count [removed] annotations from the walk, then derive optCount from
	// origCount - removedCount. This avoids mismatches when later pipeline
	// steps (e.g. removeUnusedFunctions) remove code that the optimizer saw.
	origCount := countCodeLines(original)

	var body []asmLine
	oi := 0
	opi := 0
	removedCount := 0

	for oi < len(original) {
		origLine := original[oi]

		if opi < len(optimized) && linesMatch(origLine, optimized[opi]) {
			body = append(body, optimized[opi])
			oi++
			opi++
		} else if !origLine.isCode {
			body = append(body, origLine)
			oi++
		} else {
			body = append(body, asmLine{
				text:      fmt.Sprintf("; [removed] %s", origLine.text),
				isComment: true,
			})
			removedCount++
			oi++
		}
	}

	for ; opi < len(optimized); opi++ {
		body = append(body, optimized[opi])
	}

	optCount := origCount - removedCount
	header := fmt.Sprintf("; --- peephole: %d asm lines → %d (%d saved) ---",
		origCount, optCount, removedCount)

	result := []asmLine{{text: header, isComment: true}}
	result = append(result, body...)
	return result
}

// linesMatch returns true if two asmLines represent the same instruction.
func linesMatch(a, b asmLine) bool {
	return a.isCode == b.isCode && a.isLabel == b.isLabel && a.isComment == b.isComment && a.text == b.text
}

func countCodeLines(lines []asmLine) int {
	n := 0
	for _, l := range lines {
		if l.isCode {
			n++
		}
	}
	return n
}
