"""Recompute the Index of Life in Common (edition 3) from the open input tables and compare with the published file.
Usage:  python verify-index.py [inputs.json] [index.json]
Defaults: the two files from communalcultureoflife.0118001.xyz/data/ (downloaded with the standard library only).
License: CC BY-SA 4.0 (same as the data)."""
import json, sys, urllib.request

BASE = 'https://communalcultureoflife.0118001.xyz/data/'
INPUTS = 'life-in-common-2026-10-06-v3-inputs.json'
INDEX = 'life-in-common-2026-10-06-v3.json'

def load(arg, name):
    if arg:
        return json.load(open(arg, encoding='utf-8'))
    return json.load(urllib.request.urlopen(BASE + name, timeout=60))

def percentile_scores(values, direction):
    """values: {key: x} -> {key: score 0..100}; direction +1 higher is better, -1 lower is better; ties share the mid-rank."""
    items = sorted(values.items(), key=lambda kv: kv[1])
    n = len(items); scores = {}; i = 0
    while i < n:
        j = i
        while j + 1 < n and items[j + 1][1] == items[i][1]:
            j += 1
        low = 100 * ((i + j) / 2) / (n - 1) if n > 1 else 50
        for k in range(i, j + 1):
            scores[items[k][0]] = low if direction > 0 else 100 - low
        i = j + 1
    return scores

inp = load(sys.argv[1] if len(sys.argv) > 1 else None, INPUTS)
pub = load(sys.argv[2] if len(sys.argv) > 2 else None, INDEX)
countries = inp['countries']
world_scores = {iso: {} for iso in countries}
for ind in inp['indicators']:
    w, d = ind['world'], ind['direction']
    if w == '10':
        a = percentile_scores({i: c['values']['10'][0] for i, c in countries.items()}, d)
        b = percentile_scores({i: c['values']['10b'][0] for i, c in countries.items()}, d)
        for i in countries:
            world_scores[i][w] = round((a[i] + b[i]) / 2, 1)
    else:
        s = percentile_scores({i: c['values'][w][0] for i, c in countries.items() if w in c['values']}, d)
        for i, v in s.items():
            world_scores[i][w] = round(v, 1)
rows = []
for i, sc in world_scores.items():
    if len(sc) >= inp['minWorlds']:
        rows.append({'iso3': i, 'name': countries[i]['name'], 'n': len(sc), 'overall': round(sum(sc.values()) / len(sc), 1), 'scores': sc})
rows.sort(key=lambda r: (-r['overall'], r['name']))
for k, r in enumerate(rows, 1):
    r['rank'] = k
mine = {r['iso3']: r for r in rows}
theirs = {c['iso3']: c for c in pub['countries']}
problems = []
if set(mine) != set(theirs):
    problems.append('country sets differ: %d recomputed vs %d published' % (len(mine), len(theirs)))
for iso in sorted(set(mine) & set(theirs)):
    a, b = mine[iso], theirs[iso]
    if a['scores'] != b['scores']: problems.append(iso + ' world scores differ')
    elif a['overall'] != b['overall'] or a['n'] != b['n']: problems.append(iso + ' overall or n differs')
    elif a['rank'] != b['rank']: problems.append(iso + ' rank differs')
print('recomputed %d countries, published %d, differences: %d' % (len(mine), len(theirs), len(problems)))
for p in problems[:20]:
    print(' ', p)
sys.exit(1 if problems else 0)
