"""Reproduce the 2025 fuel totals from Poppler -layout extraction of LTA MVP02-2.
Requires lta-mvp02-2-2025.txt created with pdftotext -layout.
The PDF's first four pages contain 2023-2025 rows. Use only the last Total
column, not the last number anywhere on a line (which can belong to 2024).
"""
import re, json, csv, hashlib
from pathlib import Path
from collections import defaultdict
root=Path(__file__).parent
s=(root/'lta-mvp02-2-2025.txt').read_text();pages=s.split('\f');sums=defaultdict(int);rows=[]
for pi,p in enumerate(pages[:4],1):
 header=next(l for l in p.splitlines() if l.startswith('Make/ Importer'))
 start=[m.start() for m in re.finditer(r'\bTotal\b',header)][2]
 for l in p.splitlines():
  m=re.match(r'^(.*?)\s+(AMD|PI)\s+(Diesel-Electric \(Plug-In\)|Petrol-Electric \(Plug-In\)|Petrol-Electric|Diesel-Electric|Electric|Petrol|Diesel)\s',l)
  if m:
   numbers=re.findall(r'\d[\d,]*',l[start:]); assert len(numbers)<=1,(pi,l[start:])
   n=int(numbers[0].replace(',','')) if numbers else 0
   rows.append({'page':pi,'make':m[1].strip(),'importer_type':m[2],'fuel':m[3],'count_2025':n});sums[m[3]]+=n
assert sum(sums.values())==52678,dict(sums)
assert sums['Electric']==23684,dict(sums)
with (root/'lta-extracted-2025-rows.csv').open('w') as f:
 w=csv.DictWriter(f,fieldnames=['page','make','importer_type','fuel','count_2025']);w.writeheader();w.writerows(rows)
(root/'lta-extracted-2025-rows.json').write_text(json.dumps(rows,indent=2))
result={'source_url':'https://www.lta.gov.sg/content/dam/ltagov/who_we_are/statistics_and_publications/statistics/pdf/MVP02-2_New_Cars_by_make.pdf','source_title':'Annual Vehicle Statistics 2025: Total Annual New Registration of Cars by Make','source_vintage':'2025 annual, downloaded 2026-10-01; publisher exact publication/revision date not established','pdf_sha256':hashlib.sha256((root/'lta-mvp02-2-2025.pdf').read_bytes()).hexdigest(),'rows':len(rows),'fuel_totals':dict(sums),'all_cars':sum(sums.values()),'electric_share_percent':100*sums['Electric']/sum(sums.values()),'electric_share_1dp':round(100*sums['Electric']/sum(sums.values()),1),'denominator_range_for_451_at_1dp_with_n23684':[23684*100/45.15,23684*100/45.05],'numerator_range_for_451_at_1dp_with_d52678':[52678*45.05/100,52678*45.15/100]}
result['denominator_range_semantics']='lower exclusive, upper inclusive; integer range 52457–52572'
result['numerator_range_semantics']='lower inclusive, upper exclusive; integer range 23732–23784'
result['positive_2025_rows']=sum(r['count_2025']>0 for r in rows)
(root/'calculation-results.json').write_text(json.dumps(result,indent=2));print(json.dumps(result,indent=2))
