"""Progress reporting must not share the long-lived sync session (deadlock risk)."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

import pytest
from sqlalchemy.exc import OperationalError

from app.jobs.magento_sync_worker import _persist_magento_sync_job_progress


def _deadlock_error() -> OperationalError:
    return OperationalError(
        "UPDATE magento_sync_jobs",
        {},
        Exception("deadlock detected"),
    )


def test_persist_progress_updates_job_on_separate_session():
    row = MagicMock()
    prog_session = MagicMock()
    prog_session.get.return_value = row
    ctx = MagicMock()
    ctx.__enter__.return_value = prog_session
    ctx.__exit__.return_value = False

    with patch("db.session.get_session", return_value=ctx):
        _persist_magento_sync_job_progress(
            523,
            total_count=6980,
            success_count=12,
            error_count=3,
        )

    prog_session.get.assert_called_once()
    assert row.total_count == 6980
    assert row.success_count == 12
    assert row.error_count == 3
    prog_session.commit.assert_called_once()


def test_persist_progress_retries_deadlock_then_succeeds():
    row = MagicMock()
    prog_session = MagicMock()
    prog_session.get.return_value = row
    prog_session.commit.side_effect = [_deadlock_error(), None]
    ctx = MagicMock()
    ctx.__enter__.return_value = prog_session
    ctx.__exit__.return_value = False

    with patch("db.session.get_session", return_value=ctx), patch("time.sleep"):
        _persist_magento_sync_job_progress(
            523,
            total_count=10,
            success_count=1,
            error_count=0,
        )

    assert prog_session.commit.call_count == 2


def test_persist_progress_raises_after_deadlock_retries_exhausted():
    row = MagicMock()
    prog_session = MagicMock()
    prog_session.get.return_value = row
    prog_session.commit.side_effect = _deadlock_error()
    ctx = MagicMock()
    ctx.__enter__.return_value = prog_session
    ctx.__exit__.return_value = False

    with patch("db.session.get_session", return_value=ctx), patch("time.sleep"):
        with pytest.raises(OperationalError):
            _persist_magento_sync_job_progress(
                523,
                total_count=10,
                success_count=0,
                error_count=0,
            )

    assert prog_session.commit.call_count == 3
