"""
Integration tests — Hypothesis #3: ROA_WEB grant-scoped access.

Proves:
  - ROA_WEB cannot INSERT directly into MARIUSM_AUTO.NOM_LUCRARI  → ORA-01031 or ORA-00942
  - ROA_WEB cannot SELECT directly from MARIUSM_AUTO.NOM_LUCRARI  → ORA-00942
  - ROA_WEB CAN execute SP_CREEAZA_COMANDA_PROTOTIP via EXECUTE grant → no privilege error

All tests skip gracefully when:
  - backend/secrets/roa_web.oracle_pass is absent  (user not yet created)
  - ORA-01017 on connect                           (user doesn't exist / wrong password)

Reference: docs/service-auto/grants-audit.md §3.1
"""
import os
import pytest
import oracledb

# ---------------------------------------------------------------------------
# Oracle connection constants (MARIUSM_AUTO on central server)
# ---------------------------------------------------------------------------
_HOST = "10.0.20.121"
_PORT = 1521
_SERVICE_NAME = "ROA"
_ROA_WEB_USER = "ROA_WEB"
_SECRETS_DIR = os.path.normpath(
    os.path.join(os.path.dirname(__file__), "..", "..", "..", "secrets")
)


def _read_roa_web_password() -> str | None:
    """Return ROA_WEB password from secrets file, or None if not present."""
    path = os.path.join(_SECRETS_DIR, "roa_web.oracle_pass")
    if not os.path.exists(path):
        return None
    with open(path) as f:
        return f.read().strip() or None


# ---------------------------------------------------------------------------
# Shared fixture — one connection per test module
# ---------------------------------------------------------------------------
@pytest.fixture(scope="module")
def roa_web_connection():
    """
    Yields a sync oracledb.Connection as ROA_WEB.
    Skips the whole module if the user does not yet exist on the server.
    """
    password = _read_roa_web_password()
    if not password:
        pytest.skip(
            "ROA_WEB password file not found in backend/secrets/ — "
            "user not yet created (Phase B deferred, see grants-audit.md §3)"
        )

    try:
        conn = oracledb.connect(
            user=_ROA_WEB_USER,
            password=password,
            host=_HOST,
            port=_PORT,
            service_name=_SERVICE_NAME,
        )
    except oracledb.DatabaseError as e:
        err = e.args[0]
        code = getattr(err, "code", 0)
        if code == 1017:
            pytest.skip(
                f"ROA_WEB login failed (ORA-01017: invalid username/password) — "
                "user not yet created on Oracle server"
            )
        raise  # unexpected error — let it surface

    yield conn
    conn.close()


# ---------------------------------------------------------------------------
# Negative tests — direct DML/SELECT must be rejected
# ---------------------------------------------------------------------------
@pytest.mark.integration
def test_insert_direct_fails(roa_web_connection):
    """
    ROA_WEB has no INSERT privilege on NOM_LUCRARI.
    Expected: ORA-01031 (insufficient privileges) or ORA-00942 (no table grant).
    """
    conn = roa_web_connection
    with conn.cursor() as cur:
        with pytest.raises(oracledb.DatabaseError) as exc_info:
            cur.execute(
                "INSERT INTO MARIUSM_AUTO.NOM_LUCRARI (nrord, id_mod) "
                "VALUES ('TEST_GRANT_PROBE', 1200)"
            )
        err = exc_info.value.args[0]
        assert err.code in (1031, 942), (
            f"Expected ORA-01031 or ORA-00942, got ORA-{err.code}: {err.message}"
        )


@pytest.mark.integration
def test_select_direct_fails(roa_web_connection):
    """
    ROA_WEB has no SELECT privilege on NOM_LUCRARI.
    Expected: ORA-00942 (table or view does not exist).
    """
    conn = roa_web_connection
    with conn.cursor() as cur:
        with pytest.raises(oracledb.DatabaseError) as exc_info:
            cur.execute(
                "SELECT COUNT(*) FROM MARIUSM_AUTO.NOM_LUCRARI WHERE ROWNUM < 2"
            )
            cur.fetchone()
        err = exc_info.value.args[0]
        assert err.code == 942, (
            f"Expected ORA-00942, got ORA-{err.code}: {err.message}"
        )


# ---------------------------------------------------------------------------
# Positive test — SP execution must succeed (EXECUTE grant)
# ---------------------------------------------------------------------------
@pytest.mark.integration
def test_exec_sp_succeeds(roa_web_connection):
    """
    ROA_WEB has EXECUTE on SP_CREEAZA_COMANDA_PROTOTIP.
    The SP call must not raise ORA-01031 (insufficient privileges).
    A FK violation (ORA-02291) is acceptable — it proves the SP was reached.
    Transaction is always rolled back — no test data left in prod.
    """
    conn = roa_web_connection
    with conn.cursor() as cur:
        out_id_ordl = cur.var(oracledb.NUMBER)
        out_nrord = cur.var(oracledb.STRING)

        try:
            cur.callproc(
                "MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP",
                [
                    1,                      # p_tip (FK DEV_TIP_DEVIZ)
                    1,                      # p_id_masiniclient (placeholder)
                    "TEST GRANT PROBE",     # p_solicitari
                    1,                      # p_id_firma
                    out_id_ordl,
                    out_nrord,
                ],
            )
        except oracledb.DatabaseError as e:
            conn.rollback()
            err = e.args[0]
            # ORA-02291: FK violation — SP ran, data was bad → EXECUTE grant works
            if err.code == 2291:
                return
            # ORA-01031: execution was blocked → grant missing → test must fail
            raise

        conn.rollback()  # ALWAYS rollback — never persist test data

        id_ordl = out_id_ordl.getvalue()
        nrord = out_nrord.getvalue()
        assert id_ordl is not None, "SP must return a non-null p_id_ordl"
        assert nrord, "SP must return a non-empty p_nrord"
