# retoor <retoor@molodetz.nl>

import hashlib
import time
from datetime import datetime, timedelta, timezone
from playwright.sync_api import expect
from tests.conftest import BASE_URL
from devplacepy.database import get_table
from devplacepy.utils import hash_password, generate_uid
from uuid import uuid4
from datetime import datetime, timezone
import requests
DEFAULT_MAINTENANCE_MESSAGE = (
    "DevPlace is undergoing scheduled maintenance. Please check back shortly."
)
OPERATIONAL_FIELDS = (
    "rate_limit_per_minute",
    "rate_limit_window_seconds",
    "session_max_age_days",
    "session_remember_days",
    "registration_open",
    "maintenance_mode",
    "maintenance_message",
)
def _save_settings(page, **fields):
    page.goto(f"{BASE_URL}/admin/settings", wait_until="domcontentloaded")
    for name, value in fields.items():
        locator = page.locator(f"#{name}")
        tag = locator.evaluate("el => el.tagName.toLowerCase()")
        if tag == "select":
            page.select_option(f"#{name}", value)
        else:
            locator.fill(value)
    page.click("button:has-text('Save Settings')")
    page.wait_for_url("**/admin/settings", wait_until="domcontentloaded")
def _seed_news_seo():
    from datetime import datetime, timezone
    from devplacepy.database import get_table
    from devplacepy.utils import generate_uid, make_combined_slug

    uid = generate_uid()
    title = f"SEO Test News Article {uid.split('-')[-1]}"
    slug = make_combined_slug(title, uid)
    get_table("news").insert(
        {
            "deleted_at": None,
            "deleted_by": None,
            "uid": uid,
            "slug": slug,
            "title": title,
            "description": "A seeded news article for SEO tests.",
            "content": "Body content for the seeded article.",
            "url": "https://example.com/article",
            "source_name": "ExampleSource",
            "status": "published",
            "synced_at": datetime.now(timezone.utc).isoformat(),
            "show_on_landing": 0,
            "grade": 8,
        }
    )
    return slug, uid
def _seed_owner():
    from datetime import datetime, timezone
    from uuid import uuid4
    from devplacepy.database import get_table

    uid = str(uuid4())
    get_table("users").insert(
        {
            "uid": uid,
            "username": f"seo_{uid[:8]}",
            "terms_version": "1",
            "email": f"{uid[:8]}@seo.test",
            "password_hash": "x",
            "role": "Member",
            "is_active": True,
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
    )
    return uid
def _seed_post_seo(image=None):
    from datetime import datetime, timezone
    from uuid import uuid4
    from devplacepy.database import get_table
    from devplacepy.utils import make_combined_slug

    owner = _seed_owner()
    uid = str(uuid4())
    slug = make_combined_slug("SEO Detail Post", uid)
    get_table("posts").insert(
        {
            "deleted_at": None,
            "deleted_by": None,
            "uid": uid,
            "user_uid": owner,
            "slug": slug,
            "title": "SEO Detail Post",
            "content": "Body text for the SEO detail post.",
            "topic": "general",
            "project_uid": None,
            "image": image,
            "stars": 0,
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
    )
    return slug, uid
def _seed_gist():
    from datetime import datetime, timezone
    from uuid import uuid4
    from devplacepy.database import get_table
    from devplacepy.utils import make_combined_slug

    owner = _seed_owner()
    uid = str(uuid4())
    slug = make_combined_slug("SEO Detail Gist", uid)
    get_table("gists").insert(
        {
            "deleted_at": None,
            "deleted_by": None,
            "uid": uid,
            "user_uid": owner,
            "slug": slug,
            "title": "SEO Detail Gist",
            "description": "Gist description for SEO tests.",
            "source_code": "print('seo')",
            "language": "python",
            "stars": 0,
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
    )
    return slug, uid
def _seed_project():
    from datetime import datetime, timezone
    from uuid import uuid4
    from devplacepy.database import get_table
    from devplacepy.utils import make_combined_slug

    owner = _seed_owner()
    uid = str(uuid4())
    slug = make_combined_slug("SEO Detail Project", uid)
    get_table("projects").insert(
        {
            "deleted_at": None,
            "deleted_by": None,
            "uid": uid,
            "user_uid": owner,
            "slug": slug,
            "title": "SEO Detail Project",
            "description": "Project description for SEO tests.",
            "project_type": "software",
            "platforms": "Linux",
            "status": "Released",
            "stars": 0,
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
    )
    return slug, uid
def _seed_news_image(news_uid):
    from devplacepy.database import get_table

    get_table("news_images").insert(
        {
            "deleted_at": None,
            "deleted_by": None,
            "news_uid": news_uid,
            "url": "https://example.com/seo-news-image.jpg",
        }
    )
def _seed_feed_posts(count):
    from datetime import datetime, timezone, timedelta
    from uuid import uuid4
    from devplacepy.database import get_table
    from devplacepy.utils import make_combined_slug

    owner = _seed_owner()
    topic = f"seopag{owner[:8]}"
    base = datetime(2026, 1, 1, tzinfo=timezone.utc)
    posts = get_table("posts")
    for i in range(count):
        uid = str(uuid4())
        posts.insert(
            {
                "deleted_at": None,
                "deleted_by": None,
                "uid": uid,
                "user_uid": owner,
                "slug": make_combined_slug(f"seo pag {i}", uid),
                "title": None,
                "content": f"seo pag post {i}",
                "topic": topic,
                "project_uid": None,
                "image": None,
                "stars": 0,
                "created_at": (base - timedelta(seconds=i)).isoformat(),
            }
        )
    return topic


def test_signup_page_loads(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    assert page.is_visible("h2:has-text('Join the Community')")
    assert page.is_visible("#username")
    assert page.is_visible("#email")
    assert page.is_visible("#password")
    assert page.is_visible("#confirm_password")


def test_signup_success(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "fresh_user")
    page.fill("#email", "fresh@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")
    assert page.is_visible("text=fresh_user")


def test_signup_existing_username(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "dup_user")
    page.fill("#email", "dup1@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")

    page.context.clear_cookies()
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "dup_user")
    page.fill("#email", "dup2@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    expect(page.locator("text=Username already taken")).to_be_visible()


def test_signup_existing_email(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "email_dup1")
    page.fill("#email", "sameemail@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")

    page.context.clear_cookies()
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "email_dup2")
    page.fill("#email", "sameemail@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    expect(page.locator("text=Email already registered")).to_be_visible()


def test_signup_password_mismatch(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "mismatch_user")
    page.fill("#email", "mismatch@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "different456")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    expect(page.locator("text=Passwords do not match")).to_be_visible()


def test_signup_short_password(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "shortpw_user")
    page.fill("#email", "shortpw@test.devplace")
    page.fill("#password", "ab")
    page.fill("#confirm_password", "ab")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    expect(page.locator("text=Password must be at least 6 characters")).to_be_visible()


def test_signup_invalid_username(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "ab")
    page.fill("#email", "shortname@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    expect(
        page.locator("text=Username must be between 3 and 32 characters")
    ).to_be_visible()


def test_login_link_from_signup(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.click("a:has-text('Sign in instead')")
    page.wait_for_url("**/auth/login", wait_until="domcontentloaded")


def test_password_toggle(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    pw_input = page.locator("#password")
    toggle = page.locator(".auth-toggle-pw").first
    assert pw_input.get_attribute("type") == "password"
    toggle.click()
    assert pw_input.get_attribute("type") == "text"
    toggle.click()
    assert pw_input.get_attribute("type") == "password"


def test_landing_nav_to_signup(page, app_server):
    page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
    page.click("a:has-text('Sign Up')")
    page.wait_for_url(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    assert page.is_visible("h2:has-text('Join the Community')")


def test_landing_authenticated_shows_dashboard(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "home_user")
    page.fill("#email", "home@test.devplace")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    with page.expect_navigation(timeout=10000):
        page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")

    page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
    assert page.url.rstrip("/") == BASE_URL.rstrip("/")
    assert page.is_visible("text=Welcome back")
    assert page.is_visible("text=home_user")
    feed_cta = page.locator("a.dashboard-btn-primary:has-text('New Post')")
    assert feed_cta.is_visible()
    assert feed_cta.get_attribute("href") == "/feed"
    assert not page.is_visible("text=Join DevPlace Free")


def test_registration_closed_blocks_signup(alice):
    page, _ = alice
    try:
        _save_settings(page, registration_open="0")

        signup_page = requests.get(f"{BASE_URL}/auth/signup")
        assert signup_page.status_code == 200
        assert "Registration is currently closed" in signup_page.text

        attempt = requests.post(
            f"{BASE_URL}/auth/signup",
            data={
                "username": "closed_signup",
                "email": "closed_signup@test.devplace",
                "password": "secret123",
                "confirm_password": "secret123",
                "birth_date": "1990-01-01",
                "accept_terms": "1",
            },
        )
        assert "Registration is currently closed" in attempt.text
        assert get_table("users").find_one(username="closed_signup") is None
    finally:
        _save_settings(page, registration_open="1")


def test_registration_open_allows_signup(alice):
    page, _ = alice
    try:
        _save_settings(page, registration_open="1")
        signup_page = requests.get(f"{BASE_URL}/auth/signup")
        assert "Registration is currently closed" not in signup_page.text
        assert 'name="username"' in signup_page.text
    finally:
        _save_settings(page, registration_open="1")


def test_session_length_setting_applies(alice, browser):
    page, _ = alice
    context = browser.new_context(viewport={"width": 1400, "height": 900})
    guest = context.new_page()
    guest.set_default_timeout(15000)
    try:
        _save_settings(page, session_max_age_days="1")

        username = f"sesslen_{int(time.time() * 1000)}"
        guest.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
        guest.fill("#username", username)
        guest.fill("#email", f"{username}@test.devplace")
        guest.fill("#password", "secret123")
        guest.fill("#confirm_password", "secret123")
        guest.fill("#birth_date", "1990-01-01")
        guest.check("#accept_terms")
        guest.click("button:has-text('Create account')")
        guest.wait_for_url("**/feed", wait_until="domcontentloaded")

        session_cookie = next(c for c in context.cookies() if c["name"] == "session")
        remaining = session_cookie["expires"] - time.time()
        assert 0 < remaining < 2 * 86400, remaining
    finally:
        guest.close()
        context.close()
        _save_settings(page, session_max_age_days="7")


def test_feed_page_has_unique_title(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "seo_title_test")
    page.fill("#email", "seo_title@test.dev")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")
    title = page.title()
    assert title and "Feed" in title


def test_signup_page_is_noindex(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    meta = page.locator('meta[name="robots"]')
    content = meta.get_attribute("content")
    assert content and "noindex" in content


def test_feed_page_has_canonical(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "seo_canon_test")
    page.fill("#email", "seo_canon@test.dev")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")
    link = page.locator('link[rel="canonical"]')
    href = link.get_attribute("href")
    assert href and href.startswith("http")


def test_feed_page_has_og_tags(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "seo_og_test")
    page.fill("#email", "seo_og@test.dev")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")
    og = page.locator('meta[property="og:title"]')
    content = og.get_attribute("content")
    assert content and len(content) > 0


def test_feed_page_has_twitter_card(page, app_server):
    page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded")
    page.fill("#username", "seo_twit_test")
    page.fill("#email", "seo_twit@test.dev")
    page.fill("#password", "secret123")
    page.fill("#confirm_password", "secret123")
    page.fill("#birth_date", "1990-01-01")
    page.check("#accept_terms")
    page.click("button:has-text('Create account')")
    page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded")
    card = page.locator('meta[name="twitter:card"]')
    content = card.get_attribute("content")
    assert content == "summary_large_image"
