# retoor <retoor@molodetz.nl>

import time
import requests
from tests.conftest import BASE_URL, login_user
from devplacepy.database import (
    get_table,
    get_primary_admin_uid,
    invalidate_admins_cache,
    refresh_snapshot,
)
from devplacepy.utils import clear_user_cache

_counter = [0]


def _make_admin():
    _counter[0] += 1
    name = f"ecm{int(time.time() * 1000)}{_counter[0]}"
    password = "secret123"
    requests.post(
        f"{BASE_URL}/auth/signup",
        data={
            "username": name,
            "email": f"{name}@t.dev",
            "password": password,
            "confirm_password": password,
            "birth_date": "1990-01-01",
            "accept_terms": "1",
        },
        allow_redirects=True,
    )
    refresh_snapshot()
    row = get_table("users").find_one(username=name)
    get_table("users").update({"uid": row["uid"], "role": "Admin"}, ["uid"])
    clear_user_cache(row["uid"])
    invalidate_admins_cache()
    return {
        "email": f"{name}@t.dev",
        "password": password,
        "uid": row["uid"],
        "api_key": row["api_key"],
    }


def _demote_existing_admins():
    existing = [r["uid"] for r in get_table("users").find(role="Admin")]
    for uid in existing:
        get_table("users").update({"uid": uid, "role": "Member"}, ["uid"])
    invalidate_admins_cache()
    return existing


def _restore_admins(uids):
    for uid in uids:
        get_table("users").update({"uid": uid, "role": "Admin"}, ["uid"])
    invalidate_admins_cache()


def _create_project(api_key, title, is_private=False):
    data = {
        "title": title,
        "description": "e2e container manage isolation",
        "project_type": "software",
        "status": "In Development",
    }
    if is_private:
        data["is_private"] = "on"
    r = requests.post(
        f"{BASE_URL}/projects/create",
        headers={"Accept": "application/json", "X-API-KEY": api_key},
        data=data,
    )
    assert r.status_code == 200, r.text
    return r.json()["data"]


def _insert_instance(project_uid, created_by):
    uid = f"ecm-{int(time.time() * 1000000)}"
    get_table("instances").insert(
        {
            "uid": uid,
            "slug": uid,
            "name": "e2e-manage-test",
            "project_uid": project_uid,
            "created_by": created_by,
            "owner_uid": "",
            "status": "stopped",
            "container_id": "",
            "workspace_dir": "",
            "restart_policy": "never",
            "deleted_at": None,
            "deleted_by": None,
        }
    )
    refresh_snapshot()
    return uid


def _cleanup(inst_uid):
    get_table("instances").delete(uid=inst_uid)
    refresh_snapshot()


ADMIN_CACHE_PROPAGATION_SECONDS = 5.0
ADMIN_CACHE_POLL_SECONDS = 0.2


def _await_instance_visible(api_key, inst_uid):
    deadline = time.time() + ADMIN_CACHE_PROPAGATION_SECONDS
    while time.time() < deadline:
        response = requests.get(
            f"{BASE_URL}/admin/containers/data",
            headers={"Accept": "application/json", "X-API-KEY": api_key},
        )
        if response.status_code == 200 and any(
            inst["uid"] == inst_uid for inst in response.json()["instances"]
        ):
            return
        time.sleep(ADMIN_CACHE_POLL_SECONDS)
    raise AssertionError(f"instance {inst_uid} never became visible to the viewer")


def test_admin_list_shows_view_only_for_non_owned_public_instance(page, app_server):
    owner = _make_admin()
    other = _make_admin()
    project = _create_project(owner["api_key"], "E2E Manage List Public", is_private=False)
    inst_uid = _insert_instance(project["uid"], owner["uid"])
    try:
        login_user(page, other)
        page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
        row = page.locator(f"tr.cm-row[data-uid='{inst_uid}']")
        row.wait_for(state="visible", timeout=15000)
        assert "view only" in row.inner_text().lower()
        assert row.locator("[data-cm-action='delete']").count() == 0
    finally:
        _cleanup(inst_uid)


def test_admin_list_shows_actions_for_owner(page, app_server):
    owner = _make_admin()
    project = _create_project(owner["api_key"], "E2E Manage List Owner", is_private=False)
    inst_uid = _insert_instance(project["uid"], owner["uid"])
    try:
        login_user(page, owner)
        page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
        row = page.locator(f"tr.cm-row[data-uid='{inst_uid}']")
        row.wait_for(state="visible", timeout=15000)
        assert row.locator("[data-cm-action='delete']").count() == 1
    finally:
        _cleanup(inst_uid)


def test_admin_list_excludes_others_private_project_instance(page, app_server):
    owner = _make_admin()
    other = _make_admin()
    project = _create_project(owner["api_key"], "E2E Manage List Private", is_private=True)
    inst_uid = _insert_instance(project["uid"], owner["uid"])
    try:
        login_user(page, other)
        page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
        assert page.locator(f"tr.cm-row[data-uid='{inst_uid}']").count() == 0
    finally:
        _cleanup(inst_uid)


def test_admin_detail_page_view_only_hides_manage_controls(page, app_server):
    owner = _make_admin()
    other = _make_admin()
    project = _create_project(owner["api_key"], "E2E Manage Detail Public", is_private=False)
    inst_uid = _insert_instance(project["uid"], owner["uid"])
    try:
        login_user(page, other)
        page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
        actions = page.locator("#ci-actions")
        actions.wait_for(state="visible")
        assert "view only" in actions.inner_text().lower()
        assert page.locator("#ci-term-toggle").count() == 0
        assert page.locator("[data-modal='ci-schedule-modal']").count() == 0
        assert page.locator("a:has-text('Edit configuration')").count() == 0
    finally:
        _cleanup(inst_uid)


def test_admin_detail_page_owner_sees_manage_controls(page, app_server):
    owner = _make_admin()
    project = _create_project(owner["api_key"], "E2E Manage Detail Owner", is_private=False)
    inst_uid = _insert_instance(project["uid"], owner["uid"])
    try:
        login_user(page, owner)
        page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
        page.locator("[data-modal='ci-schedule-modal']").wait_for(state="visible")
        assert page.locator("a:has-text('Edit configuration')").count() == 1
        assert page.locator("#ci-term-toggle").count() == 1
    finally:
        _cleanup(inst_uid)


def test_admin_detail_page_404_for_non_viewer_on_private_project(page, app_server):
    owner = _make_admin()
    other = _make_admin()
    project = _create_project(owner["api_key"], "E2E Manage Detail Private", is_private=True)
    inst_uid = _insert_instance(project["uid"], owner["uid"])
    try:
        login_user(page, other)
        page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
        assert page.is_visible("text=Not Found") or page.is_visible("text=404")
    finally:
        _cleanup(inst_uid)


def test_admin_edit_page_redirects_non_owner_to_detail(page, app_server):
    owner = _make_admin()
    other = _make_admin()
    project = _create_project(owner["api_key"], "E2E Manage Edit Redirect", is_private=False)
    inst_uid = _insert_instance(project["uid"], owner["uid"])
    try:
        login_user(page, other)
        page.goto(f"{BASE_URL}/admin/containers/{inst_uid}/edit", wait_until="domcontentloaded")
        page.wait_for_url(f"**/admin/containers/{inst_uid}", wait_until="domcontentloaded")
    finally:
        _cleanup(inst_uid)


def test_primary_admin_sees_and_manages_others_private_instance(page, app_server):
    restore = _demote_existing_admins()
    try:
        primary = _make_admin()
        owner = _make_admin()
        assert get_primary_admin_uid() == primary["uid"]
        project = _create_project(
            owner["api_key"], "E2E Manage Primary Private", is_private=True
        )
        inst_uid = _insert_instance(project["uid"], owner["uid"])
        try:
            _await_instance_visible(primary["api_key"], inst_uid)
            login_user(page, primary)
            page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
            row = page.locator(f"tr.cm-row[data-uid='{inst_uid}']")
            row.wait_for(state="visible", timeout=15000)
            assert row.locator("[data-cm-action='delete']").count() == 1

            page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
            page.locator("a:has-text('Edit configuration')").wait_for(state="visible")
        finally:
            _cleanup(inst_uid)
    finally:
        _restore_admins(restore)
