#!/usr/bin/env python3
"""
Match Figma cloud Drafts files (from figma-files.json) back to W{N} entries in
manifest.json by fuzzy name match, then update web/data.json with figma_key+url.
"""
import json, re, sys, difflib
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent

def normalize(s):
    s = s.lower()
    s = re.sub(r'[^a-z0-9]+', ' ', s).strip()
    return s

def best_match(target, candidates):
    """Return (score, candidate) best match from candidates list of dicts with .name"""
    nt = normalize(target)
    best = (0, None)
    for c in candidates:
        nc = normalize(c['name'])
        # exact / prefix / contains / sequence
        if nt == nc:                  s = 1.0
        elif nt in nc or nc in nt:    s = 0.85
        else:                         s = difflib.SequenceMatcher(None, nt, nc).ratio()
        if s > best[0]:
            best = (s, c)
    return best

def main():
    manifest = json.loads((ROOT/'manifest.json').read_text())
    figma_files_path = ROOT/'figma-files.json'
    if not figma_files_path.exists():
        print(f"missing {figma_files_path}", file=sys.stderr)
        sys.exit(1)
    figma_files = json.loads(figma_files_path.read_text())  # list of {key, name, ...}

    # for each W template that has fig, find matching figma file
    matches = []
    used_keys = set()
    for t in manifest['templates']:
        if not t['fig']: continue
        # use the .fig file's stem as match target (closer than archive name)
        targets = [Path(f).stem for f in t['fig']]
        # add archive stem as backup
        if t.get('archive'):
            targets.append(Path(t['archive']).stem)
        targets.append(t['name'])
        # try each target
        best_overall = (0, None)
        for tgt in targets:
            score, cand = best_match(tgt, [f for f in figma_files if f['key'] not in used_keys])
            if score > best_overall[0]:
                best_overall = (score, cand)
                if score > 0.95:
                    break
        score, cand = best_overall
        if cand and score >= 0.6:
            used_keys.add(cand['key'])
            matches.append({
                'W': t['id'], 'name': t['name'], 'fig_stem': Path(t['fig'][0]).stem if t['fig'] else None,
                'matched': cand['name'], 'key': cand['key'], 'score': round(score, 3)
            })
        else:
            matches.append({
                'W': t['id'], 'name': t['name'], 'fig_stem': Path(t['fig'][0]).stem if t['fig'] else None,
                'matched': None, 'best_score': round(best_overall[0], 3) if cand else 0,
                'best_candidate': cand['name'] if cand else None
            })

    # Update web/data.json
    data_path = ROOT/'web'/'data.json'
    data = json.loads(data_path.read_text())
    by_W = {m['W']: m for m in matches if m.get('key')}
    for t in data['templates']:
        m = by_W.get(t['id'])
        if m:
            t['figma_key'] = m['key']
            t['figma_url'] = f"https://www.figma.com/file/{m['key']}"
        else:
            t['figma_key'] = None
            t['figma_url'] = None

    # update banner with imported count
    imported = sum(1 for t in data['templates'] if t['figma_key'])
    data['imported_summary'] = (
        f"✅ <b>{imported} 个 Figma 原生文件</b>已云端就位在你的 "
        f"<a href='https://www.figma.com/files/team/1304178887825899477/drafts' target='_blank'>Figma Drafts</a>。"
        f"点卡片打开 modal 查看 iframe 实时投射 + 跳 Figma 编辑。"
    )
    data_path.write_text(json.dumps(data, ensure_ascii=False, indent=2))

    # write match report
    report = ROOT/'figma-match-report.json'
    report.write_text(json.dumps(matches, ensure_ascii=False, indent=2))
    print(f"Matched {imported}/{sum(1 for t in manifest['templates'] if t['fig'])} fig templates")
    print(f"Report: {report.relative_to(ROOT)}")
    unmatched = [m for m in matches if not m.get('key')]
    if unmatched:
        print(f"\n⚠️  {len(unmatched)} unmatched:")
        for m in unmatched:
            print(f"  {m['W']:4s} {m['name'][:50]:50s} best='{m.get('best_candidate','')[:40]}' score={m.get('best_score',0)}")

if __name__ == '__main__':
    main()
