# #region Test.ArtifactCatalogLoader [C:2] [TYPE Module]
# @RELATION  BINDS_TO -> [ArtifactCatalogLoader]
# @SEMANTICS: tests, clean-release, artifact, catalog, loader
# @PURPOSE: Validate bootstrap artifact catalog loading from JSON input.

from __future__ import annotations

import json
import pytest
from pathlib import Path
from tempfile import NamedTemporaryFile

from src.models.clean_release import CandidateArtifact


def _write_json(payload) -> str:
    """Write a JSON payload to a temp file and return its path."""
    with NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
        json.dump(payload, f)
        return f.name


# #region test_load_bootstrap_artifacts_list [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_list():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    payload = [
        {"id": "art-1", "path": "bin/app", "sha256": "abc123", "size": 1024},
        {"id": "art-2", "path": "lib/lib.so", "sha256": "def456", "size": 2048, "category": "library"},
    ]
    path = _write_json(payload)
    try:
        artifacts = load_bootstrap_artifacts(path, candidate_id="cand-1")
        assert len(artifacts) == 2
        assert isinstance(artifacts[0], CandidateArtifact)
        assert artifacts[0].id == "art-1"
        assert artifacts[0].candidate_id == "cand-1"
        assert artifacts[0].path == "bin/app"
        assert artifacts[0].sha256 == "abc123"
        assert artifacts[0].size == 1024
        assert artifacts[0].detected_category is None  # no category field on first artifact
        assert artifacts[1].detected_category == "library"  # from 'category' field on second artifact
        assert artifacts[1].size == 2048
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_list


# #region test_load_bootstrap_artifacts_object_with_artifacts_key [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_object_with_artifacts_key():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    payload = {
        "artifacts": [
            {"id": "art-1", "path": "bin/app", "sha256": "abc123", "size": 1024},
        ]
    }
    path = _write_json(payload)
    try:
        artifacts = load_bootstrap_artifacts(path, candidate_id="cand-1")
        assert len(artifacts) == 1
        assert artifacts[0].id == "art-1"
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_object_with_artifacts_key


# #region test_load_bootstrap_artifacts_empty_path [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_empty_path():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    artifacts = load_bootstrap_artifacts("", candidate_id="cand-1")
    assert artifacts == []
# #endregion test_load_bootstrap_artifacts_empty_path


# #region test_load_bootstrap_artifacts_empty_candidate_id [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_empty_candidate_id():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    payload = [{"id": "art-1", "path": "bin/app", "sha256": "abc123", "size": 1024}]
    path = _write_json(payload)
    try:
        with pytest.raises(ValueError, match="candidate_id must be non-empty"):
            load_bootstrap_artifacts(path, candidate_id="")
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_empty_candidate_id


# #region test_load_bootstrap_artifacts_not_a_list [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_not_a_list():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    payload = {"id": "art-1", "path": "bin/app", "sha256": "abc123", "size": 1024}
    path = _write_json(payload)
    try:
        with pytest.raises(ValueError, match="must be a list or an object with 'artifacts' list"):
            load_bootstrap_artifacts(path, candidate_id="cand-1")
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_not_a_list


# #region test_load_bootstrap_artifacts_missing_fields [C:2] [TYPE Function]
@pytest.mark.parametrize("missing_field", ["id", "path", "sha256"])
def test_load_bootstrap_artifacts_missing_fields(missing_field):
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    artifact = {"id": "art-1", "path": "bin/app", "sha256": "abc123", "size": 1024}
    del artifact[missing_field]

    path = _write_json([artifact])
    try:
        with pytest.raises(ValueError, match=f"missing required field '{missing_field}'"):
            load_bootstrap_artifacts(path, candidate_id="cand-1")
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_missing_fields


# #region test_load_bootstrap_artifacts_invalid_size [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_invalid_size():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    path = _write_json([{"id": "art-1", "path": "bin/app", "sha256": "abc123", "size": -1}])
    try:
        with pytest.raises(ValueError, match="must be non-negative integer"):
            load_bootstrap_artifacts(path, candidate_id="cand-1")
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_invalid_size


# #region test_load_bootstrap_artifacts_with_metadata [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_with_metadata():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    payload = [
        {
            "id": "art-1",
            "path": "bin/app",
            "sha256": "abc123",
            "size": 1024,
            "source_uri": "https://example.com/artifact",
            "source_host": "example.com",
            "detected_category": "binary",
            "metadata_json": {"version": "1.0"},
        },
        {
            "id": "art-2",
            "path": "lib/ext.so",
            "sha256": "def456",
            "size": 512,
            "extra_field": "extra_value",
        },
    ]
    path = _write_json(payload)
    try:
        artifacts = load_bootstrap_artifacts(path, candidate_id="cand-1")
        assert len(artifacts) == 2

        # Explicit metadata
        assert artifacts[0].source_uri == "https://example.com/artifact"
        assert artifacts[0].source_host == "example.com"
        assert artifacts[0].detected_category == "binary"
        assert artifacts[0].metadata_json == {"version": "1.0"}

        # Extra fields become metadata
        assert artifacts[1].metadata_json["extra_field"] == "extra_value"
        # No category/detected_category field -> detected_category is None
        assert artifacts[1].detected_category is None
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_with_metadata


# #region test_load_bootstrap_artifacts_non_dict_artifact [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_non_dict_artifact():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    path = _write_json(["not-a-dict"])
    try:
        with pytest.raises(ValueError, match="must be an object"):
            load_bootstrap_artifacts(path, candidate_id="cand-1")
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_non_dict_artifact


# #region test_load_bootstrap_artifacts_empty_id [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_empty_id():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    path = _write_json([{"id": "", "path": "bin/app", "sha256": "abc123", "size": 1024}])
    try:
        with pytest.raises(ValueError, match="missing required field 'id'|must be non-empty"):
            load_bootstrap_artifacts(path, candidate_id="cand-1")
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_empty_id


# #region test_load_bootstrap_artifacts_empty_path [C:2] [TYPE Function]
def test_load_bootstrap_artifacts_empty_path_str():
    from src.services.clean_release.artifact_catalog_loader import load_bootstrap_artifacts

    path = _write_json([{"id": "art-1", "path": "", "sha256": "abc123", "size": 1024}])
    try:
        with pytest.raises(ValueError, match="missing required field 'path'|must be non-empty"):
            load_bootstrap_artifacts(path, candidate_id="cand-1")
    finally:
        Path(path).unlink(missing_ok=True)
# #endregion test_load_bootstrap_artifacts_empty_path


# #endregion Test.ArtifactCatalogLoader
