"""Pytest fixtures for end-to-end browser tests.

Boots the Flask app in a background thread on an ephemeral port and
yields the base URL. The app uses a temp SQLite DB so e2e runs don't
contaminate the dev database.
"""

import socket
import threading

import pytest
from werkzeug.serving import make_server

from l4d2web.app import create_app
from l4d2web.auth import hash_password
from l4d2web.db import init_db, session_scope
from l4d2web.models import Blueprint, User


def _free_port() -> int:
    s = socket.socket()
    s.bind(("127.0.0.1", 0))
    port = s.getsockname()[1]
    s.close()
    return port


@pytest.fixture(scope="function")
def live_server(tmp_path, monkeypatch):
    db_path = tmp_path / "e2e.db"
    db_url = f"sqlite:///{db_path}"
    monkeypatch.setenv("DATABASE_URL", db_url)
    # app.py:57 sets SESSION_COOKIE_SECURE = not TESTING, which would
    # mark the session cookie Secure. The browser then drops it over
    # http://127.0.0.1 in e2e tests and the login flow silently fails
    # with a redirect back to /login. Force it off explicitly via the
    # env-var override (app.py:53-55) rather than flipping TESTING,
    # which would skip the SECRET_KEY guard and other production paths.
    monkeypatch.setenv("SESSION_COOKIE_SECURE", "0")
    app = create_app({"TESTING": False, "DATABASE_URL": db_url, "SECRET_KEY": "e2e"})
    # create_app() already calls init_db() inside an app context, which
    # binds tables to the in-app engine. The seed work below uses
    # session_scope() OUTSIDE any app context, which reads DATABASE_URL
    # from the environment and binds its own engine. This second init_db()
    # call creates the tables on that env-derived engine so the seed
    # inserts have somewhere to land.
    init_db()

    with session_scope() as session:
        user = User(
            username="alice",
            password_digest=hash_password("secret"),
            admin=False,
        )
        session.add(user)
        session.flush()
        bp = Blueprint(
            user_id=user.id, name="bp", arguments="[]", config="[]"
        )
        session.add(bp)
        session.flush()
        blueprint_id = bp.id
        user_id = user.id

    port = _free_port()
    server = make_server("127.0.0.1", port, app)
    thread = threading.Thread(target=server.serve_forever, daemon=True)
    thread.start()
    try:
        yield {
            "base_url": f"http://127.0.0.1:{port}",
            "user_id": user_id,
            "blueprint_id": blueprint_id,
        }
    finally:
        server.shutdown()
        thread.join(timeout=2)
