from unittest.mock import MagicMock, patch

from app.jobs.channel_jobs import _execute_channel_job


def _collection_job(*, job_type: str, channel_type: str = "shopify", options: dict | None = None):
    job = MagicMock()
    job.id = 7
    job.job_type = job_type
    job.channel_type = channel_type
    job.channel_code = "test-shop"
    job.native_connection_id = 1
    job.dry_run = False
    job.result = {"_options": options or {}}
    return job


def test_execute_collection_bootstrap_job():
    session = MagicMock()
    job = _collection_job(job_type="collection_bootstrap")
    with patch(
        "db.collection_landing_push.bootstrap_collection_landing_channel",
        return_value={"created": ["brand"], "errors": []},
    ) as bootstrap:
        result = _execute_channel_job(session, job)

    assert result["status"] == "completed"
    assert result["backend"] == "collection_landing_bootstrap"
    bootstrap.assert_called_once_with(
        session,
        channel_code="shopify",
        connection_id=1,
        dry_run=False,
    )


def test_execute_collection_push_runs_bootstrap_first():
    session = MagicMock()
    job = _collection_job(
        job_type="collection_push",
        options={"path_slug": "kitchen/anna", "bootstrap_first": True},
    )
    with patch(
        "db.collection_landing_push.bootstrap_collection_landing_channel",
        return_value={"created": ["brand"], "errors": []},
    ) as bootstrap:
        with patch(
            "db.collection_landing_push.push_collection_landing_channel",
            return_value={"pushed": 1, "skipped": 0, "errors": [], "count": 1},
        ) as push:
            result = _execute_channel_job(session, job)

    bootstrap.assert_called_once()
    push.assert_called_once()
    assert push.call_args.kwargs["path_slug"] == "kitchen/anna"
    assert result["status"] == "completed"
    assert "bootstrap" in result


def test_execute_collection_reconcile_job():
    session = MagicMock()
    job = _collection_job(
        job_type="collection_reconcile",
        options={
            "path_slug": "kitchen-cabinets/anna-stone-gray",
            "cleanup_other_paths": True,
            "sync_magento": False,
            "sync_shopify": False,
        },
    )
    reconcile_result = {
        "path_slug": "kitchen-cabinets/anna-stone-gray",
        "sku_count": 12,
        "removed_from_other_collection_paths": 3,
    }
    with patch(
        "db.collection_sku_mapping.reconcile_collection_sku_assignments",
        return_value=reconcile_result,
    ) as reconcile:
        with patch("app.jobs.channel_jobs._channel_job_progress_callback", return_value=lambda _stats: None):
            result = _execute_channel_job(session, job)

    reconcile.assert_called_once()
    assert result["status"] == "completed"
    assert result["backend"] == "collection_reconcile"
    assert result["sku_count"] == 12


def test_execute_collection_reconcile_all_job():
    session = MagicMock()
    job = _collection_job(
        job_type="collection_reconcile_all",
        options={"category_l1": "Kitchen Cabinets"},
    )
    with patch(
        "db.collection_sku_mapping.reconcile_all_collection_assignments",
        return_value={"totals": {"collections": 5, "sku_count": 40}},
    ) as reconcile_all:
        result = _execute_channel_job(session, job)

    reconcile_all.assert_called_once_with(session, category_l1="Kitchen Cabinets", dry_run=False)
    assert result["status"] == "completed"
    assert result["backend"] == "collection_reconcile_all"
    assert result["totals"]["collections"] == 5
