"""§6 hardening — the Gitea-OAuth `auth.provision_user` reconciles by email.

Regression cover for a §9-surfaced fragility: a human who signed in first via
OTC owns an email-only `users` row (`gitea_id` NULL). When they later sign in
via Gitea OAuth with the SAME email, `provision_user` used to match only by
`gitea_id`, miss the OTC row, and INSERT a new row — colliding on the
`idx_users_email` unique index and 500-ing the callback. The fix links the OAuth
identity onto the existing email row (the mirror of the OTC linker).
"""
from __future__ import annotations

from test_propose_vertical import (  # noqa: F401
    FakeGitea,
    app_with_fake_gitea,
    provision_user_row,
    tmp_env,
)


def _cfg():
    from app.config import load_config
    return load_config()


def test_oauth_links_onto_existing_otc_email_row(app_with_fake_gitea):
    from fastapi.testclient import TestClient
    from app import auth, db

    app, _fake = app_with_fake_gitea
    with TestClient(app):
        # An OTC-first user: email-only row, gitea_id NULL, still 'pending'.
        db.conn().execute(
            """
            INSERT INTO users (gitea_id, gitea_login, email, display_name, avatar_url, role, permission_state)
            VALUES (NULL, NULL, ?, ?, '', 'contributor', 'pending')
            """,
            ("dual@example.com", "dual"),
        )
        otc_id = db.conn().execute(
            "SELECT id FROM users WHERE email = ? COLLATE NOCASE", ("dual@example.com",)
        ).fetchone()["id"]

        # Now the same human signs in via Gitea OAuth (new gitea_id, same email).
        # Case-different email proves the NOCASE match.
        user = auth.provision_user(
            _cfg(),
            {"id": 9001, "login": "dualgitea", "email": "Dual@Example.com",
             "full_name": "Dual User", "avatar_url": "http://x/a.png"},
        )

        # Linked onto the SAME row — no second row, no 500.
        assert user.user_id == otc_id
        rows = db.conn().execute(
            "SELECT id, gitea_id, gitea_login, permission_state, role FROM users WHERE email = ? COLLATE NOCASE",
            ("dual@example.com",),
        ).fetchall()
        assert len(rows) == 1
        assert rows[0]["id"] == otc_id
        assert rows[0]["gitea_id"] == 9001           # OAuth identity attached
        assert rows[0]["gitea_login"] == "dualgitea"
        assert rows[0]["permission_state"] == "pending"  # admission state preserved
        assert rows[0]["role"] == "contributor"


def test_oauth_provisions_fresh_user_when_email_matches_no_one(app_with_fake_gitea):
    from fastapi.testclient import TestClient
    from app import auth, db

    app, _fake = app_with_fake_gitea
    with TestClient(app):
        user = auth.provision_user(
            _cfg(),
            {"id": 9100, "login": "freshoauth", "email": "fresh@example.com",
             "full_name": "Fresh", "avatar_url": ""},
        )
        row = db.conn().execute(
            "SELECT gitea_id, gitea_login, role, permission_state FROM users WHERE id = ?",
            (user.user_id,),
        ).fetchone()
        assert row["gitea_id"] == 9100
        assert row["gitea_login"] == "freshoauth"
        # Reaching provision_user means admission passed → granted (unchanged).
        assert row["permission_state"] == "granted"


def test_returning_oauth_user_matched_by_gitea_id_not_duplicated(app_with_fake_gitea):
    from fastapi.testclient import TestClient
    from app import auth, db

    app, _fake = app_with_fake_gitea
    with TestClient(app):
        provision_user_row(user_id=55, login="returning", role="contributor")
        before = db.conn().execute("SELECT COUNT(*) AS n FROM users").fetchone()["n"]

        user = auth.provision_user(
            _cfg(),
            {"id": 55, "login": "returning-renamed", "email": "returning@test",
             "full_name": "Returning", "avatar_url": ""},
        )
        after = db.conn().execute("SELECT COUNT(*) AS n FROM users").fetchone()["n"]

        assert user.user_id == 55
        assert after == before  # matched by gitea_id; no new row
        row = db.conn().execute(
            "SELECT gitea_login FROM users WHERE id = ?", (55,)
        ).fetchone()
        assert row["gitea_login"] == "returning-renamed"  # profile refreshed
