"""Resumaxing parser experiment. Renders one resume in many fonts/layouts to PDF,
extracts text with two open-source parsers (pypdf, pdfminer.six), scores the result.
Run: python3 run.py   (needs reportlab pypdf pdfminer.six pillow). Output: results.json + pdfs/
These are open-source parsers, NOT any employer's ATS. Read the limits in /research/ats-parser-tests/."""
import json, os, re, difflib, io
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.pagesizes import letter
import pypdf
from pdfminer.high_level import extract_text as pm_extract
from PIL import Image, ImageDraw, ImageFont

HERE = os.path.dirname(os.path.abspath(__file__)); OUT = os.path.join(HERE, 'pdfs'); os.makedirs(OUT, exist_ok=True)
SUP = '/System/Library/Fonts/Supplemental/'
FONTS = {'Arial': 'Arial.ttf', 'Georgia': 'Georgia.ttf', 'Times New Roman': 'Times New Roman.ttf', 'Verdana': 'Verdana.ttf',
         'Tahoma': 'Tahoma.ttf', 'Trebuchet MS': 'Trebuchet MS.ttf', 'Courier New': 'Courier New.ttf', 'Comic Sans MS': 'Comic Sans MS.ttf',
         'Impact': 'Impact.ttf', 'Brush Script': 'Brush Script.ttf'}
NAME = 'Priya Nair'
CONTACT = 'Bengaluru, India | +91 98765 43210 | priya.nair@example.com | linkedin.com/in/priyanair'
SECTIONS = [
 ('SUMMARY', ['Data analyst with 4 years of experience in SQL, Tableau and Python. Cut reporting time by 70%.']),
 ('WORK EXPERIENCE', ['Senior Data Analyst - Flipkart, Bengaluru | Jan 2022 - Present',
   '- Built a Tableau sales dashboard used by 40 managers, replacing 12 hours of weekly reporting.',
   '- Wrote SQL pipelines that cut report refresh time by 70% across 6 regions.',
   'Data Analyst - Infosys, Pune | Jun 2020 - Dec 2021',
   '- Identified a churn driver through cohort analysis, informing a retention campaign.']),
 ('EDUCATION', ['B.Tech, Computer Science - VIT Vellore | 2016 - 2020']),
 ('SKILLS', ['SQL, Python, Tableau, Power BI, Excel, A/B testing, statistics']),
]
def flat_lines():
    L = [NAME, CONTACT]
    for h, ls in SECTIONS: L += [h] + ls
    return L
TRUTH = flat_lines()
KEY = {'email': 'priya.nair@example.com', 'phone': '+91 98765 43210', 'name': NAME, 'dates': 'Jan 2022 - Present', 'skills': 'SQL, Python, Tableau'}

def norm(s): return re.sub(r'\s+', ' ', s).strip()
def extract(path):
    r = pypdf.PdfReader(path); a = '\n'.join((p.extract_text() or '') for p in r.pages)
    b = pm_extract(path) or ''
    return {'pypdf': a, 'pdfminer': b}
def score(text):
    t = norm(text); truth = norm(' '.join(TRUTH))
    sim = difflib.SequenceMatcher(None, truth, t, autojunk=False).ratio() if t else 0.0
    keys = {k: (v in t) for k, v in KEY.items()}
    # order integrity: consecutive truth lines that appear adjacent in output
    out_lines = [norm(x) for x in text.splitlines() if norm(x)]
    idx = {}
    for i, l in enumerate(out_lines): idx.setdefault(l, i)
    pairs = ok = 0
    for a, b in zip(TRUTH, TRUTH[1:]):
        pairs += 1
        if a in idx and b in idx and idx[b] == idx[a] + 1: ok += 1
    # chars present
    exp = norm(' '.join(SECTIONS[1][1]))
    return {'experience_intact': exp in t, 'similarity': round(sim, 3), 'keys_found': sum(keys.values()), 'keys_total': len(keys), 'keys': keys,
            'chars': len(t), 'line_order': round(ok / pairs, 3)}

from reportlab.lib.utils import simpleSplit, ImageReader
def T(c, x, y, s, font, size, w, lead=None):
    """draw wrapped text, return new y"""
    lead = lead or size + 3
    c.setFont(font, size)
    for ln in (simpleSplit(s, font, size, w) or ['']):
        c.drawString(x, y, ln); y -= lead
    return y

def draw_single(c, font, size=11, header_contact=False, footer_contact=False):
    x, y, w = 54, 740, 504
    c.setFont(font, 20); c.drawString(x, y, NAME); y -= 18
    if header_contact: c.setFont(font, 9); c.drawString(x, 775, CONTACT)
    elif footer_contact: c.setFont(font, 9); c.drawString(54, 30, CONTACT); y -= 12
    else: y = T(c, x, y, CONTACT, font, size - 1, w) - 8
    for h, ls in SECTIONS:
        c.setFont(font, size + 1); c.drawString(x, y, h); y -= 15
        for l in ls: y = T(c, x, y, l, font, size, w)
        y -= 8

def make(name, fn):
    p = os.path.join(OUT, name + '.pdf'); c = canvas.Canvas(p, pagesize=letter); fn(c); c.save(); return p

results = {'fonts': {}, 'layouts': {}}
for fam, fl in FONTS.items():
    try: pdfmetrics.registerFont(TTFont(fam, SUP + fl))
    except Exception as e: print('skip', fam, e); continue
    p = make('font-' + fam.replace(' ', '-').lower(), lambda c, f=fam: draw_single(c, f))
    ex = extract(p); results['fonts'][fam] = {k: score(v) for k, v in ex.items()}

pdfmetrics.registerFont(TTFont('Arial', SUP + 'Arial.ttf'))
CP = CONTACT.split(' | ')
LEFT = [('', CP[0]), ('', CP[1]), ('', CP[2]), ('', CP[3]), ('H', 'EDUCATION'), ('', SECTIONS[2][1][0]), ('H', 'SKILLS'), ('', SECTIONS[3][1][0])]
RIGHT = [('H', 'SUMMARY')] + [('', l) for l in SECTIONS[0][1]] + [('H', 'WORK EXPERIENCE')] + [('', l) for l in SECTIONS[1][1]]
def _col(c, items, x, w, y0=700):
    y = y0
    for k, t in items:
        y = T(c, x, y, t, 'Arial', 10, w) - (3 if k == 'H' else 0)
    return y
def layout_two_col_block(c):
    c.setFont('Arial', 20); c.drawString(54, 740, NAME)
    _col(c, LEFT, 54, 140); _col(c, RIGHT, 215, 343)       # draws whole left column first, then right
def layout_two_col_rows(c):
    # Same page as above, but drawn in row order (left cell then right cell, as many design tools/exports do)
    c.setFont('Arial', 20); c.drawString(54, 740, NAME)
    yl = yr = 700; L = list(LEFT); R = list(RIGHT)
    while L or R:
        if L: k, t = L.pop(0); yl = T(c, 54, yl, t, 'Arial', 10, 140) - (3 if k == 'H' else 0)
        if R: k, t = R.pop(0); yr = T(c, 215, yr, t, 'Arial', 10, 343) - (3 if k == 'H' else 0)
def layout_table(c):
    x0, x1, y = 54, 170, 715
    c.setFont('Arial', 20); c.drawString(x0, 745, NAME); T(c, x0, 730, CONTACT, 'Arial', 9, 504)
    y = 700
    for h, ls in SECTIONS:
        yy = y; 
        for l in ls: yy = T(c, x1, yy, l, 'Arial', 10, 388)
        hgt = y - yy + 6
        c.rect(x0, yy - 3, 504, hgt, stroke=1, fill=0)
        c.setFont('Arial', 10); c.drawString(x0 + 6, y, h)
        y = yy - 12
def layout_image(c):
    img = Image.new('RGB', (1275, 1650), 'white'); d = ImageDraw.Draw(img)
    f = ImageFont.truetype(SUP + 'Arial.ttf', 28); y = 80
    for l in TRUTH: d.text((100, y), l, fill='black', font=f); y += 44
    b = io.BytesIO(); img.save(b, 'PNG'); b.seek(0); c.drawImage(ImageReader(b), 0, 0, width=612, height=792)
def layout_skillbars(c):
    S = [s for s in SECTIONS if s[0] != 'SKILLS']
    x, y, w = 54, 740, 504; c.setFont('Arial', 20); c.drawString(x, y, NAME); y -= 18
    y = T(c, x, y, CONTACT, 'Arial', 10, w) - 8
    for h, ls in S:
        c.setFont('Arial', 12); c.drawString(x, y, h); y -= 15
        for l in ls: y = T(c, x, y, l, 'Arial', 11, w)
        y -= 8
    c.setFont('Arial', 12); c.drawString(x, y, 'SKILLS'); y -= 16
    for i in range(3):
        c.circle(x + 4, y + 3, 3, fill=1); c.rect(x + 80, y, 120, 8, fill=0); c.rect(x + 80, y, 100 - i * 15, 8, fill=1); y -= 16
LAY = {'single-column': lambda c: draw_single(c, 'Arial'),
       'two-column-sidebar-block-order': layout_two_col_block, 'two-column-sidebar-row-order': layout_two_col_rows,
       'table-layout': layout_table, 'image-only-scan': layout_image, 'skill-bars-no-text': layout_skillbars,
       'contact-in-footer': lambda c: draw_single(c, 'Arial', footer_contact=True),
       'contact-in-header-zone': lambda c: draw_single(c, 'Arial', header_contact=True)}
for n, fn in LAY.items():
    p = make('layout-' + n, fn); ex = extract(p); results['layouts'][n] = {k: score(v) for k, v in ex.items()}
    results['layouts'][n]['_sample_pypdf'] = norm(ex['pypdf'])[:520]
    results['layouts'][n]['_sample_pdfminer'] = norm(ex['pdfminer'])[:520]

json.dump(results, open(os.path.join(HERE, 'results.json'), 'w'), indent=1)
print(json.dumps({k: {n: {p: (v['similarity'], v['keys_found'], v['line_order']) for p, v in d.items() if not p.startswith('_')} for n, d in r.items()} for k, r in results.items()}, indent=1))
