"""Onboard drelenaparra.com - verify access, assign Exchange Admin role."""
import urllib.request, urllib.parse, json, sys, base64

CLAUDE_APP = "fabb3421-8b34-484b-bc17-e46de9703418"
CLAUDE_SECRET = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO"
TENANT_ID = "f06c26c7-a314-432c-a8e4-549574b6af74"
TENANT = "drelenaparra.com"

def get_token(scope):
    data = urllib.parse.urlencode({
        'client_id': CLAUDE_APP, 'client_secret': CLAUDE_SECRET,
        'scope': scope, 'grant_type': 'client_credentials'
    }).encode()
    req = urllib.request.Request(
        f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token",
        data=data, method='POST')
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())['access_token']

def graph_get(token, url):
    req = urllib.request.Request(url, headers={'Authorization': f'Bearer {token}'})
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())

def graph_post(token, url, body):
    data = json.dumps(body).encode()
    req = urllib.request.Request(url, data=data, method='POST',
        headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'})
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())

# Step 1: Get token and check permissions
print(f"[STEP 1] Getting Graph token for {TENANT}...")
token = get_token("https://graph.microsoft.com/.default")

# Decode JWT to check roles
payload = token.split('.')[1]
payload += '=' * (4 - len(payload) % 4)
decoded = json.loads(base64.urlsafe_b64decode(payload))
roles = decoded.get('roles', [])
print(f"[OK] Token acquired - {len(roles)} permissions granted")

# Step 2: List users
print(f"\n[STEP 2] Listing users...")
users = graph_get(token, f"https://graph.microsoft.com/v1.0/users?$select=displayName,userPrincipalName,mail")
for u in users.get('value', []):
    print(f"  {u['displayName']} - {u['userPrincipalName']}")

# Step 3: Find Claude SP
print(f"\n[STEP 3] Finding Claude SP...")
sp_filter = urllib.parse.quote(f"appId eq '{CLAUDE_APP}'")
sp_result = graph_get(token, f"https://graph.microsoft.com/v1.0/servicePrincipals?$filter={sp_filter}&$select=id,displayName")
if sp_result.get('value'):
    sp = sp_result['value'][0]
    sp_id = sp['id']
    print(f"[OK] SP: {sp['displayName']} (ID: {sp_id})")
else:
    print("[ERROR] SP not found")
    sys.exit(1)

# Step 4: Check granted permissions
print(f"\n[STEP 4] Checking granted permissions...")
try:
    grants = graph_get(token, f"https://graph.microsoft.com/v1.0/servicePrincipals/{sp_id}/appRoleAssignments")
    roles_granted = grants.get('value', [])
    resources = {}
    for r in roles_granted:
        res = r.get('resourceDisplayName', '?')
        resources[res] = resources.get(res, 0) + 1
    for res, count in sorted(resources.items()):
        print(f"  {res}: {count} permissions")
    print(f"  Total: {len(roles_granted)}")
except urllib.error.HTTPError as e:
    print(f"  Cannot read appRoleAssignments: HTTP {e.code}")

# Step 5: Activate and assign Exchange Admin
print(f"\n[STEP 5] Exchange Administrator role...")
try:
    roles_result = graph_get(token, "https://graph.microsoft.com/v1.0/directoryRoles?$select=id,displayName")
    exo_role = None
    for role in roles_result.get('value', []):
        if role.get('displayName') == 'Exchange Administrator':
            exo_role = role
            break

    if not exo_role:
        print("  Activating from template...")
        try:
            exo_role = graph_post(token, "https://graph.microsoft.com/v1.0/directoryRoles",
                {"roleTemplateId": "29232cdf-9323-42fd-ade2-1d097af3e4de"})
            print(f"  [OK] Activated")
        except urllib.error.HTTPError as e:
            body = e.read().decode()
            if 'already' in body.lower():
                # Re-fetch
                roles_result = graph_get(token, "https://graph.microsoft.com/v1.0/directoryRoles?$select=id,displayName")
                for role in roles_result.get('value', []):
                    if role.get('displayName') == 'Exchange Administrator':
                        exo_role = role
                        break
            else:
                print(f"  [ERROR] {e.code}: {body[:200]}")

    if exo_role:
        exo_role_id = exo_role['id']
        print(f"  Role ID: {exo_role_id}")

        # Assign
        try:
            graph_post(token, f"https://graph.microsoft.com/v1.0/directoryRoles/{exo_role_id}/members/$ref",
                {"@odata.id": f"https://graph.microsoft.com/v1.0/servicePrincipals/{sp_id}"})
            print(f"  [OK] Exchange Administrator assigned to Claude SP")
        except urllib.error.HTTPError as e:
            body = e.read().decode()
            if 'already exist' in body.lower():
                print(f"  [OK] Already assigned")
            else:
                print(f"  [WARNING] {e.code}: {body[:200]}")
except urllib.error.HTTPError as e:
    print(f"  [ERROR] Cannot manage roles: HTTP {e.code}")

# Step 6: Test access
print(f"\n[STEP 6] Testing API access...")
tests = [
    ("Users", f"https://graph.microsoft.com/v1.0/users?$top=1&$select=displayName"),
    ("Security", "https://graph.microsoft.com/v1.0/security/alerts?$top=1"),
    ("AuditLogs", "https://graph.microsoft.com/v1.0/auditLogs/signIns?$top=1"),
    ("ConditionalAccess", "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies"),
    ("Devices", "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$top=1"),
]
for name, url in tests:
    try:
        graph_get(token, url)
        print(f"  [OK] {name}")
    except urllib.error.HTTPError as e:
        print(f"  [FAIL] {name}: HTTP {e.code}")

# Step 7: Test Exchange
print(f"\n[STEP 7] Testing Exchange Online...")
try:
    exo_token = get_token("https://outlook.office365.com/.default")
    invoke_url = f"https://outlook.office365.com/adminapi/beta/{TENANT_ID}/InvokeCommand"
    cmd = json.dumps({"CmdletInput": {"CmdletName": "Get-Mailbox", "Parameters": {"ResultSize": "1"}}}).encode()
    req = urllib.request.Request(invoke_url, data=cmd, method='POST',
        headers={'Authorization': f'Bearer {exo_token}', 'Content-Type': 'application/json'})
    with urllib.request.urlopen(req) as resp:
        result = json.loads(resp.read())
    if result.get('value'):
        print(f"  [OK] Exchange Online - {result['value'][0].get('DisplayName','?')}")
    else:
        print(f"  [OK] Exchange responded (no mailboxes yet)")
except urllib.error.HTTPError as e:
    print(f"  [FAIL] Exchange: HTTP {e.code}")
except Exception as e:
    print(f"  [FAIL] Exchange: {e}")

print(f"\n{'='*50}")
print(f" ONBOARDING COMPLETE: {TENANT}")
print(f" Tenant ID: {TENANT_ID}")
print(f"{'='*50}")
