"""
Unit tests — Oracle error code → HTTP status mapping.

Tests _handle_oracle_error() directly.  No live Oracle connection required.

Covered mappings:
  ORA-20001 … ORA-20999  → HTTP 422  (business errors from RAISE_APPLICATION_ERROR)
  ORA-12541/12170/12154/12560 → HTTP 503  (Oracle network / TNS unreachable)
  ORA-01017              → HTTP 500  (bad credentials)
  ORA-00942              → HTTP 500  (missing object / grant)
  ORA-<other>            → HTTP 500  (unexpected error)
"""
import pytest
from unittest.mock import MagicMock
from fastapi import HTTPException

from backend.modules.service_auto.services.comanda_service import _handle_oracle_error


def _make_oracle_error(code: int, msg: str = "test error"):
    """
    Build a minimal mock that mimics oracledb.DatabaseError structure.
    _handle_oracle_error only accesses e.args[0].code and e.args[0].message,
    so a MagicMock is sufficient — no live oracledb import needed.
    """
    err_obj = MagicMock()
    err_obj.code = code
    err_obj.message = f"ORA-{code:05d}: {msg}"
    exc = MagicMock()
    exc.args = (err_obj,)
    return exc


# ---------------------------------------------------------------------------
# Parametrised: code → expected HTTP status + fragment in detail
# ---------------------------------------------------------------------------
@pytest.mark.parametrize("code, status, detail_fragment", [
    # Business errors — RAISE_APPLICATION_ERROR range
    (20001, 422, "mesaj business 20001"),
    (20500, 422, "mesaj business 20500"),
    (20999, 422, "mesaj business 20999"),
    # Oracle network / TNS unreachable
    (12541, 503, "indisponibil"),
    (12170, 503, "indisponibil"),
    (12154, 503, "indisponibil"),
    (12560, 503, "indisponibil"),
    # Credential / config errors
    (1017, 500, "configurare"),
    # Missing object / grant
    (942,  500, "internă"),
    # Catch-all unexpected errors
    (4031, 500, "neașteptată"),   # ORA-04031: unable to allocate memory
    (600,  500, "neașteptată"),   # ORA-00600: internal error
])
def test_error_mapping(code, status, detail_fragment):
    msg = f"mesaj business {code}" if 20001 <= code <= 20999 else "test error"
    exc = _make_oracle_error(code, msg)

    with pytest.raises(HTTPException) as exc_info:
        _handle_oracle_error(exc)

    http_exc = exc_info.value
    assert http_exc.status_code == status, (
        f"ORA-{code:05d} → expected HTTP {status}, got {http_exc.status_code}"
    )
    assert detail_fragment in http_exc.detail, (
        f"ORA-{code:05d} detail: expected '{detail_fragment}' in '{http_exc.detail}'"
    )


# ---------------------------------------------------------------------------
# ORA-20xxx: verify ORA prefix is stripped from business message
# ---------------------------------------------------------------------------
def test_20001_strips_ora_prefix():
    """The 422 detail must not contain the 'ORA-20001:' prefix."""
    exc = _make_oracle_error(20001, "Mai exista o comanda cu numarul P01-42")
    with pytest.raises(HTTPException) as exc_info:
        _handle_oracle_error(exc)
    detail = exc_info.value.detail
    assert not detail.startswith("ORA-"), (
        f"ORA prefix not stripped: '{detail}'"
    )
    assert "Mai exista" in detail


# ---------------------------------------------------------------------------
# Edge case: missing code attribute (e.g. thin-mode edge case)
# ---------------------------------------------------------------------------
def test_no_code_attribute_maps_to_500():
    """If the error object has no .code, fall through to generic 500."""
    err_obj = MagicMock(spec=[])  # spec=[] means NO attributes
    exc = MagicMock()
    exc.args = (err_obj,)

    with pytest.raises(HTTPException) as exc_info:
        _handle_oracle_error(exc)
    assert exc_info.value.status_code == 500
