import urllib.request, urllib.parse, json, os
from collections import defaultdict

APP_ID = "fabb3421-8b34-484b-bc17-e46de9703418"
TENANT_ID = "dd4a82e8-85a3-44ac-8800-07945ab4d95f"
CLIENT_SECRET = os.environ["CLIENT_SECRET"]
USER_ID = "41d14430-feb4-4ae2-aed6-2bd4e6384ca7"

token_data = urllib.parse.urlencode({
    'client_id': APP_ID, 'client_secret': CLIENT_SECRET,
    'scope': 'https://graph.microsoft.com/.default', 'grant_type': 'client_credentials'
}).encode()
req = urllib.request.Request(f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token", data=token_data, method='POST')
with urllib.request.urlopen(req) as r:
    token = json.loads(r.read())['access_token']

base = f'https://graph.microsoft.com/v1.0/users/{USER_ID}/contacts'

def patch_contact(cid, data):
    body = json.dumps(data).encode()
    req = urllib.request.Request(f'{base}/{cid}', data=body, method='PATCH',
        headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'})
    with urllib.request.urlopen(req) as r:
        return r.status

# Fetch all contacts with blank displayName
url = f'{base}?$select=id,displayName,givenName,surname,companyName,emailAddresses,businessPhones,mobilePhone&$top=999'
blanks = []
while url:
    req = urllib.request.Request(url, headers={'Authorization': f'Bearer {token}'})
    with urllib.request.urlopen(req) as r:
        data = json.loads(r.read())
    for c in data.get('value', []):
        dn = (c.get('displayName') or '').strip()
        if not dn:
            blanks.append(c)
    url = data.get('@odata.nextLink')

print(f'Found {len(blanks)} contacts with blank displayName\n')

fixed = 0
skipped = 0
for c in blanks:
    given = (c.get('givenName') or '').strip()
    surname = (c.get('surname') or '').strip()
    company = (c.get('companyName') or '').strip()
    emails = [e.get('address', '') for e in c.get('emailAddresses', []) if e.get('address', '').strip()]
    phones = list(filter(None, (c.get('businessPhones') or []) + [c.get('mobilePhone')]))

    # Build display name from best available info
    if given and surname:
        new_name = f'{given} {surname}'
    elif given:
        new_name = given
    elif surname:
        new_name = surname
    elif company:
        new_name = company
    elif emails:
        # Use email local part as name
        new_name = emails[0].split('@')[0].replace('.', ' ').replace('_', ' ').title()
    else:
        # Nothing useful - skip
        skipped += 1
        continue

    try:
        status = patch_contact(c['id'], {'displayName': new_name})
        src = 'name' if (given or surname) else ('company' if company else 'email')
        print(f'  [OK] "{new_name}" (from {src}, status {status})')
        fixed += 1
    except Exception as e:
        print(f'  [ERROR] {new_name}: {e}')

print(f'\n=== DONE: Fixed {fixed}, Skipped {skipped} (no usable data) ===')
