#!/usr/bin/env python3
"""Signal recipe 1 (hiring signal): numbers for the article, from out/recipe-1/jobs.json (recipe-1-run.mjs).
Writes out/recipe-1/results.json (every figure the article quotes) and out/recipe-1/accounts.csv (one row per
company: the account list the signal produces). Job postings only; no descriptions, no people.
Run: python3 distribution/analysis/recipe-1-analysis.py
"""
import csv, json, statistics
from collections import Counter
from datetime import date, timedelta
from pathlib import Path

HERE = Path(__file__).resolve().parent
OUT = HERE / 'out' / 'recipe-1'
d = json.loads((OUT / 'jobs.json').read_text())
runs = json.loads((OUT / 'runs.json').read_text())
jobs, names = d['items'], d['names']
first = runs[0]
snap = date.fromisoformat(first['startedAt'][:10])

OPS = ['revenue operations', 'revops', 'rev ops', 'sales operations', 'sales ops', 'gtm operations', 'go-to-market operations',
       'gtm systems', 'sales systems', 'deal desk', 'sales enablement', 'revenue enablement', 'sales strategy', 'sales compensation']
def family(t):
    return 'RevOps and sales ops' if any(k in t.lower() for k in OPS) else 'Sales leadership'
def sub(t):
    t = t.lower()
    for label, keys in [('Deal desk', ['deal desk']), ('Sales compensation', ['sales compensation']),
                        ('Enablement', ['enablement']), ('GTM / sales systems', ['gtm systems', 'sales systems']),
                        ('Revenue / sales operations', ['revenue operations', 'revops', 'rev ops', 'sales operations', 'sales ops', 'gtm operations', 'go-to-market operations', 'sales strategy'])]:
        if any(k in t for k in keys):
            return label
    return None

for j in jobs:
    j['family'] = family(j['title'])
    j['name'] = names[j['company']]

fam = Counter(j['family'] for j in jobs)
cos = {f: Counter(j['name'] for j in jobs if j['family'] == f) for f in fam}
both = sorted(set(cos['RevOps and sales ops']) & set(cos['Sales leadership']))
d30 = (snap - timedelta(days=30)).isoformat()
d7 = (snap - timedelta(days=7)).isoformat()
recent30 = [j for j in jobs if (j['postedAt'] or '') >= d30]
recent7 = [j for j in jobs if (j['postedAt'] or '') >= d7]
paid = [j for j in jobs if j['salaryMin'] is not None]
usd_year = [j for j in paid if j['salaryCurrency'] == 'USD' and j['salaryPeriod'] in ('year', None)]
def mid(j):
    return (j['salaryMin'] + (j['salaryMax'] or j['salaryMin'])) / 2
pay = {}
for label, sel in [('Sales leadership', lambda j: j['family'] == 'Sales leadership'),
                   ('Deal desk', lambda j: sub(j['title']) == 'Deal desk'),
                   ('Revenue / sales operations', lambda j: sub(j['title']) == 'Revenue / sales operations')]:
    xs = [j for j in usd_year if sel(j)]
    if xs:
        pay[label] = {'n': len(xs), 'medianMin': statistics.median(j['salaryMin'] for j in xs), 'medianMax': statistics.median(j['salaryMax'] or j['salaryMin'] for j in xs), 'medianMid': statistics.median(mid(j) for j in xs)}

# The account list: one row per company with at least one matching job.
acc = {}
for j in jobs:
    a = acc.setdefault(j['name'], {'company': j['name'], 'board': f"{j['source']}:{j['company']}", 'opsJobs': 0, 'leadershipJobs': 0, 'newestPosting': '', 'countries': Counter(), 'withPayRange': 0})
    a['opsJobs' if j['family'] == 'RevOps and sales ops' else 'leadershipJobs'] += 1
    a['newestPosting'] = max(a['newestPosting'], j['postedAt'] or '')
    if j['country']:
        a['countries'][j['country']] += 1
    a['withPayRange'] += j['salaryMin'] is not None
rows = sorted(acc.values(), key=lambda a: (-(a['opsJobs'] + a['leadershipJobs']), a['company']))
with (OUT / 'accounts.csv').open('w', newline='') as f:
    w = csv.writer(f)
    w.writerow(['company', 'board', 'revops_and_sales_ops_jobs', 'sales_leadership_jobs', 'newest_posting', 'top_countries', 'jobs_with_pay_range'])
    for a in rows:
        w.writerow([a['company'], a['board'], a['opsJobs'], a['leadershipJobs'], a['newestPosting'], ' '.join(c for c, _ in a['countries'].most_common(3)), a['withPayRange']])

res = {
    'snapshot': snap.isoformat(),
    'runs': [{k: r[k] for k in ('label', 'runId', 'status', 'seconds', 'usageTotalUsd', 'chargedEventCounts', 'itemCount')} for r in runs],
    'companiesAsked': 100,
    'jobs': len(jobs),
    'companiesHiring': len(acc),
    'families': dict(fam),
    'familyCompanies': {f: len(c) for f, c in cos.items()},
    'bothFamilies': both,
    'opsSubtypes': dict(Counter(sub(j['title']) for j in jobs if j['family'] == 'RevOps and sales ops')),
    'opsTopCompanies': cos['RevOps and sales ops'].most_common(10),
    'leadTopCompanies': cos['Sales leadership'].most_common(10),
    'topCompanies': Counter(j['name'] for j in jobs).most_common(15),
    'postedLast30Days': len(recent30), 'postedLast7Days': len(recent7),
    'companiesPostedLast30Days': len({j['name'] for j in recent30}),
    'countries': Counter(j['country'] or 'unknown' for j in jobs).most_common(10),
    'workplace': dict(Counter(j['workplaceType'] or 'not stated' for j in jobs)),
    'withPayRange': len(paid), 'payCurrencies': dict(Counter(j['salaryCurrency'] for j in paid)),
    'payUsdYear': pay,
    'ats': dict(Counter(j['source'] for j in jobs)),
    'priceStarterUsd': round(len(jobs) * 0.002 + 0.00005, 4),
}
(OUT / 'results.json').write_text(json.dumps(res, indent=1))
print(json.dumps(res, indent=1))
