"""Migration 032 — the join_requests table (§22.8 S6).

Proves: the table exists with its CHECK constraints (scope_type ∈
{project,collection}; role/status enums), the one-open-per-(scope,user) partial
unique index holds, and a decided request frees a fresh ask.
Template: test_migration_030_global_scope.py.
"""
from __future__ import annotations

import sqlite3
import tempfile
from pathlib import Path

import pytest

from app import db


class _Cfg:
    def __init__(self, path):
        self.database_path = path


def _fresh_db():
    d = tempfile.mkdtemp()
    path = Path(d) / "t.db"
    db.run_migrations(_Cfg(str(path)))
    return db.connect(str(path))


def _add_user(conn, uid, login):
    conn.execute(
        "INSERT INTO users (id, gitea_id, gitea_login, display_name, role) "
        "VALUES (?, ?, ?, ?, 'contributor')",
        (uid, uid, login, login.capitalize()),
    )


def _request(conn, scope_type="collection", scope_id="features", uid=1, role="contributor"):
    conn.execute(
        "INSERT INTO join_requests (scope_type, scope_id, requester_user_id, requested_role) "
        "VALUES (?, ?, ?, ?)",
        (scope_type, scope_id, uid, role),
    )


def test_join_request_row_round_trips():
    conn = _fresh_db()
    _add_user(conn, 1, "ben")
    _request(conn)
    row = conn.execute("SELECT * FROM join_requests WHERE requester_user_id = 1").fetchone()
    assert row["scope_type"] == "collection"
    assert row["requested_role"] == "contributor"
    assert row["status"] == "pending"
    assert row["granted_role"] is None


def test_global_scope_type_is_rejected():
    conn = _fresh_db()
    _add_user(conn, 1, "ben")
    with pytest.raises(sqlite3.IntegrityError):
        _request(conn, scope_type="global", scope_id="*")


def test_bad_role_and_status_rejected():
    conn = _fresh_db()
    _add_user(conn, 1, "ben")
    with pytest.raises(sqlite3.IntegrityError):
        _request(conn, role="viewer")
    with pytest.raises(sqlite3.IntegrityError):
        conn.execute(
            "INSERT INTO join_requests (scope_type, scope_id, requester_user_id, requested_role, status) "
            "VALUES ('project', 'ohm', 1, 'owner', 'maybe')"
        )


def test_one_open_request_per_scope_user():
    conn = _fresh_db()
    _add_user(conn, 1, "ben")
    _request(conn)
    with pytest.raises(sqlite3.IntegrityError):
        _request(conn)


def test_decided_request_frees_a_fresh_ask():
    conn = _fresh_db()
    _add_user(conn, 1, "ben")
    _request(conn)
    conn.execute("UPDATE join_requests SET status = 'declined' WHERE requester_user_id = 1")
    # a second open ask is now allowed
    _request(conn)
    n = conn.execute(
        "SELECT COUNT(*) AS n FROM join_requests WHERE requester_user_id = 1"
    ).fetchone()["n"]
    assert n == 2
