"""Roles and tenant isolation in the browser: an owner adds an Admin and changes roles; the Admin can't grant Owner or
touch the owner (desktop and mobile); a user of another workspace can't read, change or switch into Acme's data.
Run against a freshly seeded DB:  python e2e/e2e_roles.py ./e2e-shots
"""
import os, re, sys
from playwright.sync_api import sync_playwright, expect

OUT = sys.argv[1] if len(sys.argv) > 1 else "./e2e-shots"
os.makedirs(OUT, exist_ok=True)
BASE = os.environ.get("E2E_BASE", "http://localhost:3000")
errs = []

with sync_playwright() as p:
    b=p.chromium.launch(); pg=b.new_page(viewport={"width":1440,"height":900})
    errs=[]; pg.on("pageerror", lambda e: errs.append(str(e)))
    pg.goto(BASE + "/login"); pg.fill("#email","owner@acme.test"); pg.fill("#password","ChangeMe!2026"); pg.click("button[type=submit]")
    pg.wait_for_url(re.compile("/dashboard")); pg.goto(BASE + "/team")
    pg.get_by_role("button", name="Add teammate").click()
    d=pg.locator("dialog[open]")
    d.locator("#t-name").fill("Arjun Admin"); d.locator("#t-email").fill("arjun@acme.test"); d.locator("#t-pw").fill("ChangeMe!2026")
    d.locator("#t-role").select_option("customer_admin")
    expect(d.get_by_text("Runs the workspace")).to_be_visible()
    pg.screenshot(path=f"{OUT}/r01-team-add.png")
    d.get_by_role("button", name="Add teammate").click()
    expect(pg.get_by_text("Teammate added")).to_be_visible()
    pg.get_by_label("Role for Arjun Admin").select_option("customer_viewer")
    expect(pg.get_by_text("Arjun Admin is now viewer")).to_be_visible()
    pg.get_by_label("Role for Arjun Admin").select_option("customer_admin")
    expect(pg.get_by_text("Arjun Admin is now admin")).to_be_visible()
    pg.wait_for_timeout(500); pg.screenshot(path=f"{OUT}/r02-team.png")
    # Sign in as the admin: the owner row is read-only and Owner can't be granted.
    c2=b.new_context(viewport={"width":390,"height":844}); p2=c2.new_page()
    p2.goto(BASE + "/login"); p2.fill("#email","arjun@acme.test"); p2.fill("#password","ChangeMe!2026"); p2.click("button[type=submit]")
    p2.wait_for_url(re.compile("/dashboard")); p2.goto(BASE + "/team")
    expect(p2.get_by_text("Owner", exact=True)).to_be_visible()
    expect(p2.get_by_label("Role for Asha Verma")).to_have_count(0)
    p2.get_by_role("button", name="Add teammate").click()
    opts=p2.locator("#t-role option").all_inner_texts(); print("admin can grant:", opts)
    assert "Owner" not in opts
    p2.keyboard.press("Escape")
    assert p2.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
    p2.screenshot(path=f"{OUT}/r03-team-mobile-admin.png", full_page=True)
    # Cross-tenant: a user of another workspace (Bluebell Cafe) asks for Acme's records through the real app.
    acme = pg.evaluate("""async () => {
      const get = (u) => fetch(u, { headers: { 'X-Requested-With': 'devwebs' } }).then((r) => r.json());
      return { contact: (await get('/api/contacts')).data[0].id, group: (await get('/api/groups')).data[0]?.id ?? null };
    }""")
    c3=b.new_context(viewport={"width":1440,"height":900}); p3=c3.new_page()
    p3.on("pageerror", lambda e: errs.append(str(e)))
    p3.goto(BASE + "/login"); p3.fill("#email","cafe@bluebell.test"); p3.fill("#password","ChangeMe!2026"); p3.click("button[type=submit]")
    p3.wait_for_url(re.compile("/dashboard"))
    res = p3.evaluate("""async (acme) => {
      const h = { 'X-Requested-With': 'devwebs', 'X-Organization-Id': '2', 'Content-Type': 'application/json' };
      const out = {};
      out.contact = (await fetch('/api/contacts/' + acme.contact, { headers: h })).status;
      out.patch = (await fetch('/api/contacts/' + acme.contact, { method: 'PATCH', headers: h, body: JSON.stringify({ first_name: 'Hacked', phone: '+919800000001' }) })).status;
      out.switch = (await fetch('/api/auth/switch-organization', { method: 'POST', headers: h, body: JSON.stringify({ organization_id: 2 }) })).status;
      out.list = JSON.stringify(await (await fetch('/api/contacts?organization_id=2', { headers: h })).json());
      return out;
    }""", acme)
    assert res["contact"] == 404 and res["patch"] == 404 and res["switch"] in (403, 404), res
    assert "Acme" not in res["list"], res["list"][:200]
    p3.goto(BASE + "/contacts")
    p3.wait_for_load_state("networkidle"); p3.wait_for_timeout(800)
    p3.screenshot(path=f"{OUT}/r04-other-tenant-contacts.png")
    shot_text = p3.locator("main").inner_text()
    assert "acme" not in shot_text.lower()
    b.close()

if errs:
    print("\n".join(errs)); sys.exit(1)
print("roles e2e passed")
