"""
Find inline copies of a theme's section patterns inside its other patterns.

Usage (from the repo root):
    python3 .claude/skills/theme-review/scripts/copied-sections.py <theme-slug>
    python3 .claude/skills/theme-review/scripts/copied-sections.py <theme-slug> --replace

A section pattern is an insertable pattern (no `Inserter: no`) with a single
root block. Every block in another pattern file is compared with each section
pattern's root block, ignoring `patternName` and whitespace.

Output, one line per finding:
    COPY <file> <pattern-slug>              exact copy: can become a reference
    NEAR <file> <pattern-slug> <n> lines    same block name, different markup

With --replace, every COPY is replaced by <!-- wp:pattern {"slug":"…"} /-->.
Verify the result with a do_blocks() render before and after.
"""
import difflib
import glob
import os
import re
import sys

BLOCK = re.compile(r'<!-- (/?)wp:([a-z0-9/-]+)( \{.*?\})? ?(/?)-->', re.S)


def body(text):
	return text[text.index('?>') + 2:].strip() if '?>' in text else text.strip()


def spans(text):
	"""(start, end) of every block that has a closing comment."""
	out, stack = [], []
	for m in BLOCK.finditer(text):
		if m.group(4) == '/':
			continue
		if m.group(1) == '/':
			out.append((stack.pop(), m.end()))
		else:
			stack.append(m.start())
	return out


def top_level(text):
	out, depth, start = [], 0, None
	for m in BLOCK.finditer(text):
		closing, self_closing = m.group(1) == '/', m.group(4) == '/'
		if depth == 0 and not closing:
			start = m.start()
		if self_closing:
			if depth == 0:
				out.append(text[start:m.end()])
			continue
		depth += -1 if closing else 1
		if depth == 0:
			out.append(text[start:m.end()])
	return out


def norm(markup):
	markup = re.sub(r',"patternName":"[a-z0-9/-]+"', '', markup)
	markup = re.sub(r'"patternName":"[a-z0-9/-]+",?', '', markup)
	return re.sub(r'\s+', ' ', markup).strip()


def block_name(markup):
	m = re.search(r'"metadata":\{[^}]*"name":"([^"]+)"', markup.split('\n', 1)[0])
	return m.group(1) if m else None


def block_type(markup):
	m = BLOCK.search(markup)
	return m.group(2) if m else None


def main():
	theme, replace = sys.argv[1], '--replace' in sys.argv
	files = sorted(glob.glob(os.path.join(theme, 'patterns', '*.php')))
	text = {f: open(f, encoding='utf-8').read() for f in files}
	sections = {}
	for f, t in text.items():
		if re.search(r'^\s*\*\s*Inserter:\s*no', t, re.M | re.I):
			continue
		slug = re.search(r'^\s*\*\s*Slug:\s*(\S+)', t, re.M | re.I)
		roots = top_level(body(t))
		if slug and len(roots) == 1:
			sections[f] = (slug.group(1), roots[0])

	for f, t in text.items():
		hits = []
		for start, end in spans(t):
			markup = t[start:end]
			for src, (slug, root) in sections.items():
				if src == f:
					continue
				if norm(markup) == norm(root):
					hits.append((start, end, slug, 'COPY'))
				elif f not in sections and block_name(root) and block_name(markup) == block_name(root) and block_type(markup) == block_type(root):
					diff = [l for l in difflib.unified_diff(root.split('\n'), markup.split('\n'), lineterm='', n=0)
						if l[:1] in '+-' and not l.startswith(('---', '+++'))]
					hits.append((start, end, slug, 'NEAR %d lines' % len(diff)))
		# Keep the outermost match where matches nest, and an exact copy over a
		# near copy of another pattern on the same block.
		hits.sort(key=lambda h: (h[0], -(h[1] - h[0]), h[3] != 'COPY'))
		kept, last = [], -1
		for h in hits:
			if h[0] >= last:
				kept.append(h)
				last = h[1]
		for start, end, slug, kind in kept:
			print('%s %s %s' % (kind.split(' ')[0], f, slug) + ('' if kind == 'COPY' else ' ' + kind.split(' ', 1)[1]))
		if replace:
			new = t
			for start, end, slug, kind in sorted(kept, reverse=True):
				if kind == 'COPY':
					new = new[:start] + '<!-- wp:pattern {"slug":"%s"} /-->' % slug + new[end:]
			if new != t:
				open(f, 'w', encoding='utf-8').write(new)


if __name__ == '__main__':
	main()
