"""Tests for extended CLI commands (including transcode/compression profile options)."""

import io
import json
import tempfile
import threading
import time
from pathlib import Path
from unittest.mock import patch, MagicMock

import numpy as np
import pytest
import torch
import torch.nn as nn

from model_osmosis.format.image import OsmoImage
from model_osmosis.cli import (
    build_parser,
    cmd_expand,
    cmd_expand_status,
    cmd_expand_rollback,
    cmd_make,
    cmd_protect,
    cmd_check,
    cmd_launch,
    cmd_artifact_track,
    cmd_artifact_verify,
    cmd_artifact_hook_install,
    cmd_demo,
    cmd_doctor,
    cmd_benchmark_runtime,
    cmd_optimize_status,
    cmd_optimize_reset,
    cmd_pipeline,
    cmd_images,
    cmd_register,
    cmd_pull,
    cmd_transcode,
    cmd_push,
    cmd_convert,
    cmd_diff,
    cmd_validate,
    cmd_verify,
    cmd_quantize,
    cmd_serve,
    cmd_history,
    cmd_release_check,
    _run_unified_pipeline,
    _run_weight_merge_backend,
    LoadedModelRef,
    _parse_model_ref,
    _auto_detect_model_scheme,
    _parse_onnx_input_shape,
    _check_trust_for_action,
    _pipeline_report_payload,
    _ensure_windows_auto_register,
    _resolve_strategy_engine_mode,
    _resolve_compression_engine_mode,
)
from model_osmosis.optimizer.self_optimize import record_subsystem_selection


@pytest.fixture(autouse=True)
def _trust_home_tmp(monkeypatch, tmp_path):
    monkeypatch.setenv("OSMOSIS_TRUST_HOME", str(tmp_path / "trust"))


def _make_model(seed=0):
    torch.manual_seed(seed)
    model = nn.Sequential(
        nn.Linear(6, 16),
        nn.ReLU(),
        nn.Linear(16, 8),
        nn.ReLU(),
        nn.Linear(8, 3),
    )
    model.eval()
    return model


def _build_and_save(tmpdir, name="test-model", seed=0):
    """Build an .osmoimg and save it, return the path."""
    model = _make_model(seed)
    image = OsmoImage.build(model, name=name)
    path = Path(tmpdir) / f"{name}.osmoimg"
    image.save(path)
    return path


class TestParserHasAllCommands:
    """Verify all commands are registered."""

    def test_all_commands_registered(self):
        parser = build_parser()
        # Get all subcommand names
        subparsers_actions = [
            action for action in parser._subparsers._actions
            if isinstance(action, type(parser._subparsers._actions[0]))
            and hasattr(action, '_parser_class')
        ]
        # Find the subparser action
        for action in parser._subparsers._actions:
            if hasattr(action, 'choices') and action.choices:
                commands = list(action.choices.keys())
                break

        expected = [
            "make", "protect", "check", "launch",
            "expand", "expand-status", "expand-rollback",
            "build", "demo", "run", "inspect", "export", "register",
            "merge", "obfuscate", "compare", "benchmark", "info", "version",
            "images", "pull", "transcode", "push", "convert", "diff",
            "validate", "verify", "artifact", "trust", "quantize", "serve", "history", "pipeline",
            "doctor", "benchmark-runtime", "release-check", "optimize-status", "optimize-reset",
        ]
        for cmd in expected:
            assert cmd in commands, f"Command '{cmd}' not registered"

    def test_each_new_command_has_help(self):
        parser = build_parser()
        new_commands = ["make", "protect", "check", "launch", "expand", "expand-status", "expand-rollback", "artifact", "demo", "doctor", "images", "pull", "transcode", "push", "convert", "diff",
                        "benchmark-runtime",
                        "pipeline",
                        "validate", "verify", "trust", "quantize", "serve", "history", "release-check",
                        "optimize-status", "optimize-reset"]
        for action in parser._subparsers._actions:
            if hasattr(action, 'choices') and action.choices:
                for cmd in new_commands:
                    assert cmd in action.choices, f"{cmd} missing"
                    sub = action.choices[cmd]
                    assert sub.description is not None, f"{cmd} has no description"

    def test_build_parser_has_compression_profile(self):
        parser = build_parser()
        parsed = parser.parse_args(["build", "foo/bar", "--compression-profile", "legacy"])
        assert parsed.compression_profile == "legacy"
        assert parsed.compression_engine == "auto"
        assert parsed.trust_sign is True
        assert parsed.provenance == "private"
        assert parsed.repro_mode == "strict"

    def test_make_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["make", "--mode", "merge", "--models", "a", "b"])
        assert parsed.func == cmd_make
        assert parsed.mode == "merge"
        assert parsed.output_type == "osmo"
        assert parsed.merge_strategy == "auto"
        assert parsed.coverage_floor == pytest.approx(0.70)
        assert parsed.seed == 42
        assert parsed.self_check is True
        assert parsed.self_check_level == "smoke"

    def test_make_parser_supports_cross_merge_mode(self):
        parser = build_parser()
        parsed = parser.parse_args(
            ["make", "--mode", "cross-merge", "--models", "a", "b", "--output-type", "osmoimg"]
        )
        assert parsed.mode == "cross-merge"
        assert parsed.output_type == "osmoimg"

    def test_protect_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["protect", "foo/bar"])
        assert parsed.func == cmd_protect
        assert parsed.compression_profile == "lossless-max"
        assert parsed.trust_sign is True
        assert parsed.provenance == "private"
        assert parsed.repro_mode == "strict"
        assert parsed.signer_backend == "local-keyring"

    def test_expand_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["expand", "pt:model.pt"])
        assert parsed.func == cmd_expand
        assert parsed.model_ref == "pt:model.pt"
        assert parsed.task == "auto"
        assert parsed.dataset is None
        assert parsed.data_mode == "auto"
        assert parsed.max_download_gb == pytest.approx(1.0)
        assert parsed.data_ttl_hours == pytest.approx(168.0)
        assert parsed.allow_licenses == []
        assert parsed.offline is False
        assert parsed.target_params is None
        assert parsed.budget_minutes == 5
        assert parsed.budget_ram_gb == pytest.approx(1.5)
        assert parsed.seed == 42
        assert parsed.output is None
        assert parsed.export_format == "osmoimg"
        assert parsed.optimizer_mode == "auto"
        assert parsed.fallback_mode == "off"

    def test_expand_status_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["expand-status"])
        assert parsed.func == cmd_expand_status
        assert parsed.name is None
        assert parsed.json is False

    def test_expand_rollback_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["expand-rollback", "--to", "my_model.r0003"])
        assert parsed.func == cmd_expand_rollback
        assert parsed.to == "my_model.r0003"

    def test_check_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["check", "model.osmoimg"])
        assert parsed.func == cmd_check
        assert parsed.image == "model.osmoimg"
        assert parsed.self_check_level == "smoke"
        assert parsed.trust_profile == "standard"
        assert parsed.policy_file is None
        assert parsed.json is False

    def test_launch_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["launch", "model.osmoimg"])
        assert parsed.func == cmd_launch
        assert parsed.action == "run"
        assert parsed.runtime_profile == "default"
        assert parsed.device == "auto"
        assert parsed.runtime_quantization == "none"
        assert parsed.runtime_cache is True
        assert parsed.require_trust is False
        assert parsed.trust_profile == "standard"

    def test_artifact_parser_track_verify_hook(self):
        parser = build_parser()
        parsed_track = parser.parse_args(["artifact", "track", "model.osmoimg"])
        assert parsed_track.func == cmd_artifact_track
        assert parsed_track.images == ["model.osmoimg"]

        parsed_verify = parser.parse_args(["artifact", "verify", "--all", "--json"])
        assert parsed_verify.func == cmd_artifact_verify
        assert parsed_verify.all is True
        assert parsed_verify.json is True

        parsed_hook = parser.parse_args(["artifact", "hook", "install", "--force"])
        assert parsed_hook.func == cmd_artifact_hook_install
        assert parsed_hook.force is True

    def test_demo_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["demo"])
        assert parsed.func == cmd_demo
        assert parsed.model_id == "HuggingFaceTB/SmolLM2-135M-Instruct"
        assert parsed.output == "models/quick_demo_smollm2_135m_instruct.osmoimg"
        assert parsed.compression_profile == "lossless-max"
        assert parsed.timeout_minutes == 30.0

    def test_doctor_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["doctor"])
        assert parsed.func == cmd_doctor
        assert parsed.compression_profile == "lossless-max"

    def test_benchmark_runtime_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["benchmark-runtime", "model.osmoimg"])
        assert parsed.func == cmd_benchmark_runtime
        assert parsed.image == "model.osmoimg"
        assert parsed.profile == "i5_2gb"
        assert parsed.iterations == 5
        assert parsed.warmup_runs == 2
        assert parsed.runtime_profile == "default"
        assert parsed.device == "auto"
        assert parsed.runtime_quantization == "none"
        assert parsed.runtime_cache is True
        assert parsed.max_tokens == 32
        assert parsed.temperature == 0.0
        assert parsed.json is False

    def test_run_parser_runtime_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["run", "model.osmoimg", "--prompt", "hi"])
        assert parsed.runtime_profile == "default"
        assert parsed.device == "auto"
        assert parsed.runtime_quantization == "none"
        assert parsed.runtime_cache is True
        assert parsed.include_prompt is False
        assert parsed.trust_profile == "standard"

    def test_run_parser_include_prompt_flag(self):
        parser = build_parser()
        parsed = parser.parse_args(
            ["run", "model.osmoimg", "--prompt", "hi", "--include-prompt"]
        )
        assert parsed.include_prompt is True

    def test_register_parser_icon_flag(self):
        parser = build_parser()
        parsed = parser.parse_args(["register", "--icon", "osmoimg icon.ico"])
        assert parsed.func == cmd_register
        assert parsed.icon == "osmoimg icon.ico"


class TestAutoRegister:
    def test_auto_register_skips_when_disabled(self):
        with patch("model_osmosis.cli.platform.system", return_value="Windows"), \
             patch("model_osmosis.cli._auto_register_enabled", return_value=False), \
             patch("model_osmosis.format.file_format.register_file_format") as reg_fn:
            _ensure_windows_auto_register("run")
        reg_fn.assert_not_called()

    def test_auto_register_skips_when_already_registered(self):
        with patch("model_osmosis.cli.platform.system", return_value="Windows"), \
             patch("model_osmosis.cli._auto_register_enabled", return_value=True), \
             patch("model_osmosis.cli._is_windows_osmoimg_registered", return_value=True), \
             patch("model_osmosis.format.file_format.register_file_format") as reg_fn:
            _ensure_windows_auto_register("run")
        reg_fn.assert_not_called()

    def test_auto_register_calls_register_with_packaged_icon(self):
        with patch("model_osmosis.cli.platform.system", return_value="Windows"), \
             patch("model_osmosis.cli._auto_register_enabled", return_value=True), \
             patch("model_osmosis.cli._is_windows_osmoimg_registered", return_value=False), \
             patch("model_osmosis.cli._packaged_osmoimg_icon_path", return_value="C:\\icons\\osmoimg_icon.ico"), \
             patch("model_osmosis.format.file_format.register_file_format") as reg_fn:
            _ensure_windows_auto_register("run")
        reg_fn.assert_called_once_with(
            verbose=False,
            icon_path="C:\\icons\\osmoimg_icon.ico",
        )

    def test_serve_parser_runtime_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["serve", "model.osmoimg"])
        assert parsed.runtime_profile == "default"
        assert parsed.device == "auto"
        assert parsed.runtime_quantization == "none"
        assert parsed.runtime_cache is True
        assert parsed.warmup is False
        assert parsed.trust_profile == "standard"

    def test_release_check_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["release-check"])
        assert parsed.func == cmd_release_check
        assert parsed.local_only is False
        assert parsed.with_ci is True
        assert parsed.strict_ci is True
        assert parsed.json is False

    def test_verify_parser_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(["verify", "model.osmoimg"])
        assert parsed.image == "model.osmoimg"
        assert parsed.require_trust is False
        assert parsed.policy_file is None
        assert parsed.repro_check is False
        assert parsed.json is False

    def test_trust_subcommands_parse(self):
        parser = build_parser()
        parsed_keygen = parser.parse_args(["trust", "keygen", "--name", "default"])
        assert parsed_keygen.name == "default"
        parsed_list = parser.parse_args(["trust", "list-keys"])
        assert parsed_list.trust_command == "list-keys"
        parsed_import = parser.parse_args(
            ["trust", "import-signer", "--name", "alice", "--pubkey", "alice.pub"]
        )
        assert parsed_import.name == "alice"
        assert parsed_import.pubkey == "alice.pub"

class TestReleaseCheckCommand:
    def test_release_check_local_only_skips_ci(self, capsys):
        parser = build_parser()
        args = parser.parse_args(["release-check", "--local-only", "--json"])

        with patch("model_osmosis.cli._default_release_local_gates", return_value=[]), \
             patch("model_osmosis.cli._collect_release_ci_status") as ci_mock:
            cmd_release_check(args)

        out = capsys.readouterr().out
        payload = json.loads(out[out.find("{"):])
        assert payload["status"] == "PASS"
        assert payload["ci"]["checked"] is False
        ci_mock.assert_not_called()

    def test_release_check_fails_when_ci_unavailable_in_strict_mode(self):
        parser = build_parser()
        args = parser.parse_args(["release-check", "--json"])

        with patch("model_osmosis.cli._default_release_local_gates", return_value=[]), \
             patch(
                 "model_osmosis.cli._collect_release_ci_status",
                 return_value={
                     "available": False,
                     "reason": "gh auth missing",
                     "workflows": {},
                     "current_sha": "abc123",
                 },
             ), \
             patch("model_osmosis.cli._current_git_sha", return_value="abc123"):
            with pytest.raises(RuntimeError, match="ci-status-unavailable"):
                cmd_release_check(args)

    def test_release_check_fails_when_required_workflow_missing_for_sha(self):
        parser = build_parser()
        args = parser.parse_args(["release-check", "--json"])

        workflows = {
            "clean-machine-validation": {
                "status": "completed",
                "conclusion": "success",
                "url": "http://example/clean",
                "updated_at": "2026-03-09T00:00:00Z",
                "head_sha": "abc123",
            },
            "trusted-osmoimg": {
                "status": "missing",
                "conclusion": "",
                "url": "",
                "updated_at": "",
                "head_sha": "",
            },
            "runtime-benchmark": {
                "status": "completed",
                "conclusion": "success",
                "url": "http://example/runtime",
                "updated_at": "2026-03-09T00:00:00Z",
                "head_sha": "abc123",
            },
            "cross-framework-reliability": {
                "status": "completed",
                "conclusion": "success",
                "url": "http://example/crossfw",
                "updated_at": "2026-03-09T00:00:00Z",
                "head_sha": "abc123",
            },
        }
        with patch("model_osmosis.cli._default_release_local_gates", return_value=[]), \
             patch(
                 "model_osmosis.cli._collect_release_ci_status",
                 return_value={
                     "available": True,
                     "reason": "",
                     "passed": False,
                     "workflows": workflows,
                     "current_sha": "abc123",
                 },
             ), \
             patch("model_osmosis.cli._current_git_sha", return_value="abc123"):
            with pytest.raises(RuntimeError, match="ci-release-workflows"):
                cmd_release_check(args)


class TestUnifiedFourCommandRouting:
    def test_cmd_make_routes_cross_merge_to_pipeline(self):
        parser = build_parser()
        args = parser.parse_args(
            [
                "make",
                "--mode",
                "cross-merge",
                "--models",
                "a",
                "b",
                "--output-type",
                "osmo",
            ]
        )

        with patch("model_osmosis.cli.cmd_pipeline") as pipeline_mock:
            cmd_make(args)

        pipeline_mock.assert_called_once()
        pipeline_args = pipeline_mock.call_args[0][0]
        assert pipeline_args.mode == "merge"
        assert pipeline_args.force_cross is True
        assert pipeline_args.output_type == "osmo"
        assert pipeline_args.merge_strategy == "auto"

    def test_cmd_protect_routes_to_build(self):
        parser = build_parser()
        args = parser.parse_args(
            [
                "protect",
                "foo/bar",
                "-o",
                "protected.osmoimg",
                "--compression-profile",
                "legacy",
            ]
        )

        with patch("model_osmosis.cli.cmd_build") as build_mock:
            cmd_protect(args)

        build_mock.assert_called_once()
        build_args = build_mock.call_args[0][0]
        assert build_args.model == "foo/bar"
        assert build_args.output == "protected.osmoimg"
        assert build_args.compression_profile == "legacy"

    def test_cmd_launch_routes_by_action(self):
        parser = build_parser()
        run_args = parser.parse_args(["launch", "model.osmoimg", "--action", "run", "--prompt", "hi"])
        serve_args = parser.parse_args(["launch", "model.osmoimg", "--action", "serve", "--port", "9000"])
        export_args = parser.parse_args(
            ["launch", "model.osmoimg", "--action", "export", "--format", "onnx", "-o", "out.onnx"]
        )

        with patch("model_osmosis.cli.cmd_run") as run_mock, \
             patch("model_osmosis.cli.cmd_serve") as serve_mock, \
             patch("model_osmosis.cli.cmd_export") as export_mock:
            cmd_launch(run_args)
            cmd_launch(serve_args)
            cmd_launch(export_args)

        run_mock.assert_called_once()
        serve_mock.assert_called_once()
        export_mock.assert_called_once()
        assert run_mock.call_args[0][0].prompt == "hi"
        assert serve_mock.call_args[0][0].port == 9000
        assert export_mock.call_args[0][0].format == "onnx"

    def test_cmd_check_outputs_json_contract(self, capsys):
        parser = build_parser()
        args = parser.parse_args(["check", "model.osmoimg", "--json"])

        with patch("model_osmosis.format.image.OsmoImage.inspect", return_value={
            "runtime": {"payload_codec": "adaptive-zstd-v1", "compression_profile": "lossless-max"},
        }), \
             patch("model_osmosis.cli._check_trust_for_action", return_value={"trust_status": "trusted"}), \
             patch("model_osmosis.cli._pipeline_self_check", return_value={
                 "self_check_status": "passed",
                 "self_check_level": "smoke",
                 "self_check_checks": ["artifact_exists"],
                 "self_check_skips": [],
             }):
            cmd_check(args)

        out = capsys.readouterr().out
        payload = json.loads(out[out.find("{"):])
        assert payload["status"] == "PASS"
        assert payload["trust_status"] == "trusted"
        assert payload["self_check_status"] == "passed"


class TestArtifactTrackingCommands:
    def test_artifact_track_and_verify_all(self, tmp_path, monkeypatch, capsys):
        monkeypatch.chdir(tmp_path)
        image_path = _build_and_save(tmp_path, "artifact-track", seed=21)

        parser = build_parser()
        track_args = parser.parse_args(["artifact", "track", str(image_path)])
        track_args.func(track_args)
        capsys.readouterr()

        lock_file = tmp_path / ".model_osmosis" / "artifacts.lock.json"
        assert lock_file.exists()

        verify_args = parser.parse_args(["artifact", "verify", "--all", "--json"])
        verify_args.func(verify_args)
        out = capsys.readouterr().out
        payload = json.loads(out[out.find("{"):])
        assert payload["status"] == "PASS"
        assert payload["checked_artifacts"] == 1
        assert payload["failed_artifacts"] == 0

    def test_artifact_verify_detects_drift(self, tmp_path, monkeypatch):
        monkeypatch.chdir(tmp_path)
        image_path = _build_and_save(tmp_path, "artifact-drift", seed=31)
        parser = build_parser()

        track_args = parser.parse_args(["artifact", "track", str(image_path)])
        track_args.func(track_args)

        # Overwrite artifact with different model payload to simulate changed shipped version.
        replacement = OsmoImage.build(_make_model(32), name="artifact-drift")
        replacement.save(image_path)

        verify_args = parser.parse_args(["artifact", "verify", str(image_path)])
        with pytest.raises(RuntimeError, match="artifact verify failed"):
            verify_args.func(verify_args)

    def test_artifact_hook_install_writes_pre_commit_and_pre_push(self, tmp_path, monkeypatch):
        hooks_dir = tmp_path / ".git" / "hooks"
        hooks_dir.mkdir(parents=True, exist_ok=True)
        parser = build_parser()
        args = parser.parse_args(["artifact", "hook", "install"])

        with patch("model_osmosis.services.artifact_tracking._resolve_git_hooks_dir", return_value=hooks_dir):
            args.func(args)

        pre_commit = hooks_dir / "pre-commit"
        pre_push = hooks_dir / "pre-push"
        assert pre_commit.exists()
        assert pre_push.exists()
        assert "model-osmosis-artifact-hook-v1" in pre_commit.read_text(encoding="utf-8")
        assert "osmosis artifact verify --all" in pre_push.read_text(encoding="utf-8")


class TestCmdImages:
    def test_lists_osmoimg_files(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            _build_and_save(tmpdir, "model-a", seed=0)
            _build_and_save(tmpdir, "model-b", seed=1)

            args = MagicMock()
            args.directory = tmpdir
            cmd_images(args)

            output = capsys.readouterr().out
            assert "model-a" in output
            assert "model-b" in output
            assert "2 image(s) found" in output

    def test_empty_directory(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            args = MagicMock()
            args.directory = tmpdir
            cmd_images(args)

            output = capsys.readouterr().out
            assert "No .osmoimg files found" in output

    def test_nonexistent_directory(self, capsys):
        args = MagicMock()
        args.directory = "/nonexistent/path/12345"
        cmd_images(args)
        output = capsys.readouterr().err
        assert "Directory not found" in output


class TestCmdDiff:
    def test_diff_same_images(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path_a = _build_and_save(tmpdir, "diff-a", seed=0)
            path_b = _build_and_save(tmpdir, "diff-b", seed=1)

            args = MagicMock()
            args.image_a = str(path_a)
            args.image_b = str(path_b)
            cmd_diff(args)

            output = capsys.readouterr().out
            assert "Model" in output
            assert "Architecture" in output
            assert "Runtime" in output
            assert "Image" in output

    def test_diff_identical_images(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "same", seed=0)

            args = MagicMock()
            args.image_a = str(path)
            args.image_b = str(path)
            cmd_diff(args)

            output = capsys.readouterr().out
            # Same image compared to itself should show equality markers
            assert "=" in output


class TestCmdValidate:
    def test_valid_image(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "valid-test")

            args = MagicMock()
            args.image = str(path)
            cmd_validate(args)

            output = capsys.readouterr().out
            assert "Magic bytes valid" in output
            assert "Header valid" in output
            assert "Zip payload valid" in output
            assert "Manifest valid" in output
            assert "Parameters loadable" in output
            assert "Image is valid" in output

    def test_invalid_file(self, capsys):
        with tempfile.NamedTemporaryFile(suffix=".osmoimg", delete=False) as f:
            f.write(b"NOT A VALID OSMOIMG FILE")
            f.flush()

            args = MagicMock()
            args.image = f.name
            cmd_validate(args)

            output = capsys.readouterr().out
            assert "Invalid magic bytes" in output

    def test_nonexistent_file(self, capsys):
        args = MagicMock()
        args.image = "/nonexistent/model.osmoimg"
        cmd_validate(args)

        output = capsys.readouterr().out
        assert "File not found" in output


class TestCmdVerify:
    def test_verify_unsigned_image(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            model = _make_model(42)
            image = OsmoImage.build(model, name="verify-unsigned", trust_sign=False)
            image_path = Path(tmpdir) / "verify-unsigned.osmoimg"
            image.save(image_path, trust_sign=False)

            args = MagicMock()
            args.image = str(image_path)
            args.require_trust = False
            args.policy_file = None
            args.repro_check = False
            args.json = False
            cmd_verify(args)

            out = capsys.readouterr().out
            assert "VERIFY" in out
            assert "unsigned" in out

    def test_verify_repro_check_included(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "verify-repro")
            args = MagicMock()
            args.image = str(path)
            args.require_trust = False
            args.policy_file = None
            args.repro_check = True
            args.json = False

            with patch(
                "model_osmosis.cli._run_repro_check",
                return_value={"checked": True, "passed": True, "mode": "strict-serialization"},
            ):
                cmd_verify(args)

            out = capsys.readouterr().out
            assert "Repro check:" in out
            assert "PASS" in out

    def test_verify_policy_file_blocks_unsigned(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            model = _make_model(43)
            image = OsmoImage.build(model, name="verify-policy-unsigned", trust_sign=False)
            image_path = Path(tmpdir) / "verify-policy-unsigned.osmoimg"
            image.save(image_path, trust_sign=False)

            policy_path = Path(tmpdir) / "policy.json"
            policy_path.write_text(
                json.dumps({"required_trust_status": "trusted"}),
                encoding="utf-8",
            )

            args = MagicMock()
            args.image = str(image_path)
            args.require_trust = False
            args.policy_file = str(policy_path)
            args.repro_check = False
            args.json = False

            with pytest.raises(RuntimeError, match="Verification blocked by policy"):
                cmd_verify(args)


class TestTrustPolicyEnforcement:
    def test_check_trust_for_action_writes_audit_log(self, tmp_path, monkeypatch):
        trust_home = tmp_path / "trust-home"
        monkeypatch.setenv("OSMOSIS_TRUST_HOME", str(trust_home))

        model = _make_model(11)
        image = OsmoImage.build(model, name="policy-audit")
        image_path = tmp_path / "policy-audit.osmoimg"
        image.save(image_path)

        policy_path = tmp_path / "policy.json"
        policy_path.write_text(
            json.dumps(
                {
                    "required_trust_status": "trusted",
                    "min_header_version": 3,
                }
            ),
            encoding="utf-8",
        )

        result = _check_trust_for_action(
            str(image_path),
            action="run",
            require_trust=False,
            policy_file=str(policy_path),
        )
        assert result["trust_status"] == "trusted"
        assert result["policy_result"]["passed"] is True

        audit_path = trust_home / "audit" / "events.jsonl"
        assert audit_path.exists()
        lines = [line.strip() for line in audit_path.read_text(encoding="utf-8").splitlines() if line.strip()]
        assert len(lines) >= 1
        event = json.loads(lines[-1])
        assert event["action"] == "run"
        assert event["policy_result"]["checked"] is True

    def test_check_trust_for_action_blocks_on_policy_violation(self, tmp_path, monkeypatch):
        trust_home = tmp_path / "trust-home"
        monkeypatch.setenv("OSMOSIS_TRUST_HOME", str(trust_home))

        model = _make_model(12)
        image = OsmoImage.build(model, name="policy-fail", trust_sign=False)
        image_path = tmp_path / "policy-fail.osmoimg"
        image.save(image_path, trust_sign=False)

        policy_path = tmp_path / "policy.json"
        policy_path.write_text(
            json.dumps({"required_trust_status": "trusted"}),
            encoding="utf-8",
        )

        with pytest.raises(RuntimeError, match="blocked by policy") as exc_info:
            _check_trust_for_action(
                str(image_path),
                action="export",
                require_trust=False,
                policy_file=str(policy_path),
            )
        assert str(exc_info.value).count("Next command:") == 1

    def test_production_trust_profile_requires_policy_file(self, tmp_path, monkeypatch):
        trust_home = tmp_path / "trust-home"
        monkeypatch.setenv("OSMOSIS_TRUST_HOME", str(trust_home))

        model = _make_model(13)
        image = OsmoImage.build(model, name="prod-profile", trust_sign=False)
        image_path = tmp_path / "prod-profile.osmoimg"
        image.save(image_path, trust_sign=False)

        with pytest.raises(RuntimeError, match="requires a policy file") as exc_info:
            _check_trust_for_action(
                str(image_path),
                action="run",
                require_trust=False,
                policy_file=None,
                trust_profile="production",
            )
        assert str(exc_info.value).count("Next command:") == 1

    def test_production_trust_profile_requires_allowlist(self, tmp_path, monkeypatch):
        trust_home = tmp_path / "trust-home"
        monkeypatch.setenv("OSMOSIS_TRUST_HOME", str(trust_home))

        model = _make_model(14)
        image = OsmoImage.build(model, name="prod-no-allowlist")
        image_path = tmp_path / "prod-no-allowlist.osmoimg"
        image.save(image_path)

        policy_path = tmp_path / "policy.json"
        policy_path.write_text(
            json.dumps(
                {
                    "required_trust_status": "trusted",
                    "min_header_version": 3,
                }
            ),
            encoding="utf-8",
        )

        with pytest.raises(RuntimeError, match="requires non-empty allowed_signer_ids or allowed_key_ids"):
            _check_trust_for_action(
                str(image_path),
                action="serve",
                require_trust=False,
                policy_file=str(policy_path),
                trust_profile="production",
            )

    def test_production_trust_profile_passes_with_allowlist(self, tmp_path, monkeypatch):
        trust_home = tmp_path / "trust-home"
        monkeypatch.setenv("OSMOSIS_TRUST_HOME", str(trust_home))

        model = _make_model(15)
        image = OsmoImage.build(model, name="prod-allowlist")
        image_path = tmp_path / "prod-allowlist.osmoimg"
        image.save(image_path)

        policy_path = tmp_path / "policy.json"
        policy_path.write_text(
            json.dumps(
                {
                    "min_header_version": 3,
                    "required_trust_status": "trusted",
                    "allowed_signer_ids": ["default"],
                }
            ),
            encoding="utf-8",
        )

        result = _check_trust_for_action(
            str(image_path),
            action="export",
            require_trust=False,
            policy_file=str(policy_path),
            trust_profile="production",
        )
        assert result["trust_status"] == "trusted"
        assert result["policy_result"]["passed"] is True

class TestCmdQuantize:
    def test_quantize_int8(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "quant-test")
            output_path = str(Path(tmpdir) / "quantized.osmoimg")

            args = MagicMock()
            args.image = str(path)
            args.bits = 8
            args.output = output_path
            cmd_quantize(args)

            output = capsys.readouterr().out
            assert "Quantizing to 8-bit" in output
            assert Path(output_path).exists()

            # Load and verify
            loaded = OsmoImage.load(output_path)
            assert loaded.runtime.quantization == "int8"

    def test_quantize_fp16(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "quant16-test")
            output_path = str(Path(tmpdir) / "quantized16.osmoimg")

            args = MagicMock()
            args.image = str(path)
            args.bits = 16
            args.output = output_path
            cmd_quantize(args)

            output = capsys.readouterr().out
            assert "Quantizing to 16-bit" in output

            loaded = OsmoImage.load(output_path)
            assert loaded.runtime.quantization == "fp16"

    def test_quantize_int4(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "quant4-test")
            output_path = str(Path(tmpdir) / "quantized4.osmoimg")

            args = MagicMock()
            args.image = str(path)
            args.bits = 4
            args.output = output_path
            cmd_quantize(args)

            loaded = OsmoImage.load(output_path)
            assert loaded.runtime.quantization == "int4"


class TestCmdHistory:
    def test_shows_history(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "history-test")

            args = MagicMock()
            args.image = str(path)
            cmd_history(args)

            output = capsys.readouterr().out
            assert "Build History" in output
            assert "Built at:" in output
            assert "Source framework:" in output
            assert "Encrypted:" in output
            assert "history-test" in output


class TestCmdConvert:
    def test_convert_osmoimg_to_pytorch(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "convert-test")
            output_path = str(Path(tmpdir) / "converted.pt")

            args = MagicMock()
            args.model = str(path)
            args.to = "pytorch"
            args.output = output_path
            args.seed = 42
            args.allow_partial_load = False
            args.allow_lossy_cast = False
            cmd_convert(args)

            output = capsys.readouterr().out
            assert "Loading .osmoimg" in output
            assert "Exporting to pytorch" in output


class TestCmdServe:
    def test_serve_starts_server(self):
        """Test that the serve command creates a working HTTP server."""
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "serve-test")

            args = MagicMock()
            args.image = str(path)
            args.host = "127.0.0.1"
            args.port = 0  # Let OS pick a free port

            # We can't easily test serve_forever, but we can verify
            # PredictHandler is constructed properly by testing the
            # parser accepts serve args
            parser = build_parser()
            parsed = parser.parse_args(["serve", str(path), "--port", "9999", "--host", "127.0.0.1"])
            assert parsed.func == cmd_serve
            assert parsed.port == 9999
            assert parsed.host == "127.0.0.1"

    def test_serve_warms_runtime_with_runtime_flags(self):
        class _DummyRuntime:
            source_framework = "pytorch"
            model_type = "causal_lm"

        class _DummyImage:
            name = "serve-dummy"
            parameter_count = 123
            is_encrypted = True
            runtime = _DummyRuntime()

            def __init__(self):
                self.warm_calls = []

            def summary(self):
                return "dummy summary"

            def warm_runtime(self, **kwargs):
                self.warm_calls.append(kwargs)
                return {}

            def run(self, **kwargs):
                return "ok"

        class _DummyServer:
            def __init__(self, addr, handler):
                self.addr = addr
                self.handler = handler

            def serve_forever(self):
                return None

        dummy_image = _DummyImage()
        args = MagicMock()
        args.image = "dummy.osmoimg"
        args.host = "127.0.0.1"
        args.port = 8080
        args.runtime_profile = "cpu-lowram"
        args.device = "cpu"
        args.runtime_quantization = "int8"
        args.runtime_cache = True
        args.warmup = True
        args.require_trust = False
        args.policy_file = None

        with patch("model_osmosis.cli._check_trust_for_action"), \
             patch("model_osmosis.format.image.OsmoImage.load", return_value=dummy_image), \
             patch("http.server.HTTPServer", _DummyServer):
            cmd_serve(args)

        assert len(dummy_image.warm_calls) == 1
        warm_call = dummy_image.warm_calls[0]
        assert warm_call["runtime_profile"] == "cpu-lowram"
        assert warm_call["device"] == "cpu"
        assert warm_call["runtime_quantization"] == "int8"
        assert warm_call["runtime_cache"] is True
        assert warm_call["warmup_runs"] == 1


class TestCmdPull:
    def test_pull_parser(self):
        parser = build_parser()
        parsed = parser.parse_args(["pull", "user/MyModel", "-o", "out.osmoimg"])
        assert parsed.func == cmd_pull
        assert parsed.model == "user/MyModel"
        assert parsed.output == "out.osmoimg"
        assert parsed.compression_profile == "legacy"
        assert parsed.compression_engine == "auto"
        assert parsed.trust_sign is True
        assert parsed.provenance == "private"
        assert parsed.repro_mode == "strict"

    def test_pull_default_output(self):
        parser = build_parser()
        parsed = parser.parse_args(["pull", "user/MyModel"])
        assert parsed.output is None
        assert parsed.compression_profile == "legacy"
        assert parsed.compression_engine == "auto"
        assert parsed.trust_sign is True


class TestCmdDemo:
    def test_demo_missing_dependency_returns_actionable_error(self):
        args = MagicMock()
        args.model_id = "HuggingFaceTB/SmolLM2-135M-Instruct"
        args.output = "models/demo.osmoimg"
        args.compression_profile = "lossless-max"
        args.max_tokens = 32
        args.temperature = 0.1
        args.timeout_minutes = 30.0

        with patch("model_osmosis.cli._require_demo_dependencies", side_effect=RuntimeError("Install with: pip install \"osmosis[huggingface,compression]\"")):
            with pytest.raises(RuntimeError, match="Install with: pip install"):
                cmd_demo(args)

    def test_demo_flow_calls_build_save_inspect_load_run(self, capsys):
        args = MagicMock()
        args.model_id = "HuggingFaceTB/SmolLM2-135M-Instruct"
        args.output = "models/demo.osmoimg"
        args.compression_profile = "lossless-max"
        args.max_tokens = 16
        args.temperature = 0.0
        args.timeout_minutes = 30.0

        calls = []

        class _DummyRuntime:
            min_ram_gb = 1.8
            payload_codec = "adaptive-zstd-v1"
            compression_profile = "lossless-max"

        class _DummyBuildImage:
            runtime = _DummyRuntime()
            name = "quick-demo"
            parameter_count = 123

            def save(self, path, compression_profile=None):
                calls.append(("save", str(path), compression_profile))
                return Path(path)

        class _DummyLoadedImage:
            def run(self, prompt, max_tokens=None, temperature=None):
                calls.append(("run", prompt, max_tokens, temperature))
                return "hello from demo"

        def _fake_build(*args_, **kwargs_):
            calls.append(("build", kwargs_.get("model"), kwargs_.get("compression_profile")))
            return _DummyBuildImage()

        def _fake_inspect(path):
            calls.append(("inspect", str(path)))
            return {
                "runtime": {
                    "source_framework": "huggingface",
                    "model_type": "causal_lm",
                    "min_ram_gb": 1.8,
                    "supports_cpu": True,
                    "is_encrypted": True,
                    "payload_codec": "adaptive-zstd-v1",
                    "compression_profile": "lossless-max",
                    "trust_status": "trusted",
                },
                "image": {
                    "file_size_mb": 120.0,
                    "original_size_mb": 300.0,
                },
            }

        def _fake_load(path):
            calls.append(("load", str(path)))
            return _DummyLoadedImage()

        with patch("model_osmosis.cli._require_demo_dependencies"), \
             patch("model_osmosis.cli._check_hf_network"), \
             patch("model_osmosis.cli._demo_api_smoke", return_value={"api_url": "http://127.0.0.1:7777"}), \
             patch("model_osmosis.format.image.OsmoImage.build", side_effect=_fake_build), \
             patch("model_osmosis.format.image.OsmoImage.inspect", side_effect=_fake_inspect), \
             patch("model_osmosis.format.image.OsmoImage.load", side_effect=_fake_load):
            cmd_demo(args)

        output = capsys.readouterr().out
        assert "Quick Demo Summary" in output
        assert "PASS" in output
        assert "Output path:" in output
        assert "Min RAM:" in output
        assert "Payload codec:" in output
        assert "Compression profile:" in output
        assert "Elapsed:" in output

        call_names = [c[0] for c in calls]
        assert call_names == ["build", "save", "inspect", "load", "run"]


class TestCmdDoctor:
    def test_doctor_pass_output_contract(self, capsys):
        args = MagicMock()
        args.compression_profile = "lossless-max"

        with patch("model_osmosis.cli._is_module_available", return_value=True), \
             patch("model_osmosis.cli._check_hf_network"), \
             patch("model_osmosis.cli._get_available_ram_gb", return_value=4.0), \
             patch("model_osmosis.cli.shutil.disk_usage", return_value=MagicMock(free=5 * 1024 ** 3)):
            cmd_doctor(args)

        out = capsys.readouterr().out
        assert "DOCTOR" in out
        assert "Doctor status:" in out
        assert "PASS" in out

    def test_doctor_fails_with_actionable_message(self):
        args = MagicMock()
        args.compression_profile = "lossless-max"

        with patch("model_osmosis.cli._is_module_available", side_effect=lambda m: m != "zstandard"), \
             patch("model_osmosis.cli._check_hf_network"), \
             patch("model_osmosis.cli._get_available_ram_gb", return_value=4.0), \
             patch("model_osmosis.cli.shutil.disk_usage", return_value=MagicMock(free=5 * 1024 ** 3)):
            with pytest.raises(RuntimeError, match="Environment checks failed"):
                cmd_doctor(args)


class TestCmdBenchmarkRuntime:
    def test_benchmark_runtime_outputs_json_schema(self, capsys):
        class _DummyImage:
            def run(self, prompt, max_tokens=None, temperature=None, **kwargs):
                return "benchmark output"

            def warm_runtime(self, **kwargs):
                return {}

        args = MagicMock()
        args.image = "model.osmoimg"
        args.profile = "i5_2gb"
        args.baseline_file = "benchmarks/runtime_baselines.json"
        args.iterations = 3
        args.prompt = "hello"
        args.max_tokens = 8
        args.temperature = 0.0
        args.warmup_runs = 2
        args.runtime_profile = "default"
        args.device = "auto"
        args.runtime_quantization = "none"
        args.runtime_cache = True
        args.json = True

        baseline = {
            "i5_2gb": {
                "max_cold_start_seconds": 999.0,
                "max_peak_rss_mb": 99999.0,
                "max_first_token_latency_seconds": 999.0,
                "max_warm_first_token_latency_seconds": 999.0,
                "min_tokens_per_second": 0.01,
                "max_p95_latency_seconds": 999.0,
            }
        }

        with patch("model_osmosis.format.image.OsmoImage.load", return_value=_DummyImage()), \
             patch("model_osmosis.cli._load_runtime_baselines", return_value=baseline), \
             patch("model_osmosis.cli._current_rss_mb", return_value=128.0):
            cmd_benchmark_runtime(args)

        out = capsys.readouterr().out
        payload = json.loads(out[out.find("{"):])
        assert payload["profile"] == "i5_2gb"
        assert payload["passed"] is True
        assert "cold_start_seconds" in payload
        assert "peak_rss_mb" in payload
        assert "first_token_latency_seconds" in payload
        assert "warm_first_token_latency_seconds" in payload
        assert "tokens_per_second" in payload
        assert "p95_latency_seconds" in payload

    def test_benchmark_runtime_regression_raises(self):
        class _DummyImage:
            def run(self, prompt, max_tokens=None, temperature=None, **kwargs):
                return "benchmark output"

            def warm_runtime(self, **kwargs):
                return {}

        args = MagicMock()
        args.image = "model.osmoimg"
        args.profile = "ci_standard"
        args.baseline_file = "benchmarks/runtime_baselines.json"
        args.iterations = 1
        args.prompt = "hello"
        args.max_tokens = 4
        args.temperature = 0.0
        args.warmup_runs = 1
        args.runtime_profile = "default"
        args.device = "auto"
        args.runtime_quantization = "none"
        args.runtime_cache = True
        args.json = False

        baseline = {
            "ci_standard": {
                "max_cold_start_seconds": 0.000001,
                "max_peak_rss_mb": 1.0,
                "max_first_token_latency_seconds": 0.000001,
                "max_warm_first_token_latency_seconds": 0.000001,
                "min_tokens_per_second": 1000000.0,
                "max_p95_latency_seconds": 0.000001,
            }
        }

        with patch("model_osmosis.format.image.OsmoImage.load", return_value=_DummyImage()), \
             patch("model_osmosis.cli._load_runtime_baselines", return_value=baseline), \
             patch("model_osmosis.cli._current_rss_mb", return_value=256.0):
            with pytest.raises(RuntimeError, match="Runtime benchmark regression detected"):
                cmd_benchmark_runtime(args)

    def test_benchmark_runtime_falls_back_to_generic_mode(self, capsys):
        class _DummyImage:
            class _DummyOsmo:
                parameters = {"layer.weight": np.zeros((4, 8), dtype=np.float32)}

            osmo_model = _DummyOsmo()

            def run(self, prompt=None, input_data=None, max_tokens=None, temperature=None, **kwargs):
                if prompt is not None:
                    raise TypeError("'NoneType' object is not callable")
                assert input_data is not None
                return np.ones((1, 4), dtype=np.float32)

            def warm_runtime(self, **kwargs):
                return {}

        args = MagicMock()
        args.image = "model.osmoimg"
        args.profile = "ci_standard"
        args.baseline_file = "benchmarks/runtime_baselines.json"
        args.iterations = 2
        args.prompt = "hello"
        args.max_tokens = 8
        args.temperature = 0.0
        args.warmup_runs = 2
        args.runtime_profile = "default"
        args.device = "auto"
        args.runtime_quantization = "none"
        args.runtime_cache = True
        args.json = True

        baseline = {
            "ci_standard": {
                "max_cold_start_seconds": 999.0,
                "max_peak_rss_mb": 99999.0,
                "max_first_token_latency_seconds": 999.0,
                "max_warm_first_token_latency_seconds": 999.0,
                "min_tokens_per_second": 0.01,
                "max_p95_latency_seconds": 999.0,
            }
        }

        with patch("model_osmosis.format.image.OsmoImage.load", return_value=_DummyImage()), \
             patch("model_osmosis.cli._load_runtime_baselines", return_value=baseline), \
             patch("model_osmosis.cli._current_rss_mb", return_value=200.0):
            cmd_benchmark_runtime(args)

        out = capsys.readouterr().out
        payload = json.loads(out[out.find("{"):])
        assert payload["passed"] is True
        assert payload["execution_mode"] == "generic"


class TestCmdTranscode:
    def test_transcode_parser(self):
        parser = build_parser()
        parsed = parser.parse_args(["transcode", "model.osmoimg"])
        assert parsed.func == cmd_transcode
        assert parsed.image == "model.osmoimg"
        assert parsed.compression_profile == "lossless-max"
        assert parsed.compression_engine == "auto"
        assert parsed.trust_sign is True
        assert parsed.upgrade_trust is False
        assert parsed.signer_backend == "local-keyring"
        assert parsed.migration_report is None

    def test_transcode_default_output(self, capsys):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "transcode-src")
            args = MagicMock()
            args.image = str(path)
            args.output = None
            args.compression_profile = "legacy"
            args.trust_sign = True
            args.upgrade_trust = False
            args.signer_id = "default"
            args.signer_backend = "local-keyring"
            args.migration_report = None

            cmd_transcode(args)
            output = capsys.readouterr().out
            assert "TRANSCODE" in output
            assert Path(tmpdir, "transcode-src.v2.osmoimg").exists()

    def test_transcode_writes_migration_report(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "transcode-report")
            out = Path(tmpdir) / "transcode-report.v2.osmoimg"
            report = Path(tmpdir) / "migration.json"

            args = MagicMock()
            args.image = str(path)
            args.output = str(out)
            args.compression_profile = "legacy"
            args.trust_sign = True
            args.upgrade_trust = False
            args.signer_id = "default"
            args.signer_backend = "local-keyring"
            args.migration_report = str(report)

            cmd_transcode(args)

            assert report.exists()
            payload = json.loads(report.read_text(encoding="utf-8"))
            assert payload["input_image"] == str(path)
            assert payload["output_image"] == str(out)
            assert payload["tokenizer_validation_status"] in {
                "real_assets",
                "placeholder_only",
                "missing_or_corrupt",
            }

    def test_transcode_to_lossless_max(self):
        pytest.importorskip("zstandard")
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "transcode-v2")
            out = Path(tmpdir) / "transcode-v2.v2.osmoimg"

            args = MagicMock()
            args.image = str(path)
            args.output = str(out)
            args.compression_profile = "lossless-max"
            args.trust_sign = True
            args.upgrade_trust = False
            args.signer_id = "default"
            args.signer_backend = "local-keyring"
            args.migration_report = None
            cmd_transcode(args)

            original = OsmoImage.load(path)
            loaded = OsmoImage.load(out)
            assert loaded.runtime.compression_profile == "lossless-max"
            for name, arr in original.osmo_model.parameters.items():
                assert loaded.osmo_model.parameters[name].tobytes() == arr.tobytes()

    def test_transcode_upgrade_trust_signs_unsigned_image(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            model = _make_model(99)
            image = OsmoImage.build(model, name="unsigned-src", trust_sign=False)
            src = Path(tmpdir) / "unsigned-src.osmoimg"
            image.save(src, trust_sign=False)

            out = Path(tmpdir) / "unsigned-src.v2.osmoimg"
            args = MagicMock()
            args.image = str(src)
            args.output = str(out)
            args.compression_profile = "legacy"
            args.trust_sign = True
            args.upgrade_trust = True
            args.signer_id = "default"
            args.signer_backend = "local-keyring"
            args.migration_report = None

            cmd_transcode(args)
            verify = OsmoImage.verify(out)
            assert verify["trust_status"] in {"trusted", "signed_untrusted"}

    def test_transcode_can_explicitly_disable_trust_signing(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            path = _build_and_save(tmpdir, "transcode-no-sign")
            out = Path(tmpdir) / "transcode-no-sign.v2.osmoimg"

            args = MagicMock()
            args.image = str(path)
            args.output = str(out)
            args.compression_profile = "legacy"
            args.trust_sign = False
            args.upgrade_trust = False
            args.signer_id = "default"
            args.signer_backend = "local-keyring"
            args.migration_report = None

            cmd_transcode(args)
            verify = OsmoImage.verify(out)
            assert verify["trust_status"] == "unsigned"


class TestCmdPush:
    def test_push_parser(self):
        parser = build_parser()
        parsed = parser.parse_args(["push", "model.osmoimg", "user/repo", "--private"])
        assert parsed.func == cmd_push
        assert parsed.image == "model.osmoimg"
        assert parsed.repo == "user/repo"
        assert parsed.private is True

    def test_push_public_default(self):
        parser = build_parser()
        parsed = parser.parse_args(["push", "model.osmoimg", "user/repo"])
        assert parsed.private is False


class TestCmdQuantizeParser:
    def test_quantize_parser_requires_bits(self):
        parser = build_parser()
        with pytest.raises(SystemExit):
            parser.parse_args(["quantize", "model.osmoimg"])

    def test_quantize_parser_valid_bits(self):
        parser = build_parser()
        for bits in [4, 8, 16]:
            parsed = parser.parse_args(["quantize", "model.osmoimg", "--bits", str(bits)])
            assert parsed.bits == bits


class TestCmdConvertParser:
    def test_convert_parser_requires_to(self):
        parser = build_parser()
        with pytest.raises(SystemExit):
            parser.parse_args(["convert", "model.pt"])

    def test_convert_parser_valid(self):
        parser = build_parser()
        parsed = parser.parse_args(["convert", "model.pt", "--to", "tensorflow", "-o", "out/"])
        assert parsed.to == "tensorflow"
        assert parsed.output == "out/"
        assert parsed.seed == 42
        assert parsed.allow_partial_load is False
        assert parsed.allow_lossy_cast is False


def _pipeline_args(**overrides):
    args = MagicMock()
    args.mode = "merge"
    args.output_type = "osmoimg"
    args.models = ["pt:a.pt", "pt:b.pt"]
    args.source = None
    args.target = None
    args.output = "models/pipeline_test.osmoimg"
    args.name = "pipeline-test"
    args.compression_profile = "lossless-max"
    args.compression_engine = "auto"
    args.sample_data = None
    args.auto_grow = True
    args.merge_strategy = "auto"
    args.strategy_engine = "auto"
    args.cross_opt_stage = "auto"
    args.weights = None
    args.coverage_floor = 0.70
    args.top_k = 2
    args.train_gate = True
    args.hf_base_model = None
    args.onnx_input_shape = None
    args.trace_input_shape = None
    args.epochs = 3
    args.seed = 42
    args.allow_partial_load = False
    args.allow_lossy_cast = False
    args.trust_sign = True
    args.provenance = "private"
    args.repro_mode = "strict"
    args.signer_id = "default"
    args.signer_backend = "local-keyring"
    args.dry_run = False
    args.report_file = None
    args.self_check = True
    args.self_check_level = "smoke"
    for key, value in overrides.items():
        setattr(args, key, value)
    return args


class TestPipelineParserAndHelpers:
    def test_pipeline_parser_requires_mode_and_output_type(self):
        parser = build_parser()
        with pytest.raises(SystemExit):
            parser.parse_args(["pipeline"])

    def test_pipeline_parser_merge_shape(self):
        parser = build_parser()
        parsed = parser.parse_args(
            [
                "pipeline",
                "--mode", "merge",
                "--output-type", "osmoimg",
                "--models", "hf:foo/bar", "pt:model.pt",
            ]
        )
        assert parsed.func == cmd_pipeline
        assert parsed.mode == "merge"
        assert parsed.output_type == "osmoimg"
        assert parsed.models == ["hf:foo/bar", "pt:model.pt"]
        assert parsed.compression_profile == "lossless-max"
        assert parsed.seed == 42
        assert parsed.allow_partial_load is False
        assert parsed.allow_lossy_cast is False
        assert parsed.trust_sign is True
        assert parsed.provenance == "private"
        assert parsed.repro_mode == "strict"
        assert parsed.cross_opt_stage == "auto"
        assert parsed.dry_run is False
        assert parsed.report_file is None
        assert parsed.self_check is True
        assert parsed.self_check_level == "smoke"

    def test_pipeline_parser_weight_merge_defaults(self):
        parser = build_parser()
        parsed = parser.parse_args(
            [
                "pipeline",
                "--mode", "weight-merge",
                "--output-type", "pytorch",
                "--models", "pt:a.pt", "pt:b.pt",
            ]
        )
        assert parsed.mode == "weight-merge"
        assert parsed.coverage_floor == 0.70
        assert parsed.merge_strategy == "auto"
        assert parsed.strategy_engine == "auto"

    def test_pipeline_parser_runtime_flags(self):
        parser = build_parser()
        parsed = parser.parse_args(
            [
                "pipeline",
                "--mode", "merge",
                "--output-type", "osmoimg",
                "--models", "pt:a.pt", "pt:b.pt",
                "--dry-run",
                "--report-file", "reports/pipeline.json",
                "--no-self-check",
                "--cross-opt-stage", "shadow",
            ]
        )
        assert parsed.dry_run is True
        assert parsed.report_file == "reports/pipeline.json"
        assert parsed.self_check is False
        assert parsed.self_check_level == "smoke"
        assert parsed.compression_engine == "auto"
        assert parsed.cross_opt_stage == "shadow"

    def test_merge_parser_strategy_engine_default(self):
        parser = build_parser()
        parsed = parser.parse_args(["merge", "pt:a.pt", "pt:b.pt"])
        assert parsed.strategy == "auto"
        assert parsed.strategy_engine == "auto"
        assert parsed.cross_opt_stage == "auto"

    def test_strategy_engine_env_override(self, monkeypatch):
        monkeypatch.setenv("OSMOSIS_STRATEGY_ENGINE", "off")
        assert _resolve_strategy_engine_mode("auto") == "off"

    def test_compression_engine_env_override(self, monkeypatch):
        monkeypatch.setenv("OSMOSIS_OPTIMIZER", "off")
        assert _resolve_compression_engine_mode("auto") == "off"

    def test_optimize_commands_parse(self):
        parser = build_parser()
        parsed_status = parser.parse_args(["optimize-status", "--json"])
        assert parsed_status.func == cmd_optimize_status
        assert parsed_status.json is True
        parsed_reset = parser.parse_args(["optimize-reset"])
        assert parsed_reset.func == cmd_optimize_reset
        assert parsed_reset.json is False

    def test_pipeline_parser_supports_11_output_types(self):
        parser = build_parser()
        output_types = [
            "osmoimg", "osmo", "pytorch", "hf", "onnx",
            "tensorflow", "keras", "jax", "flax", "safetensors", "torchscript",
        ]
        for out in output_types:
            parsed = parser.parse_args(
                [
                    "pipeline",
                    "--mode", "merge",
                    "--output-type", out,
                    "--models", "pt:a.pt", "pt:b.pt",
                ]
            )
            assert parsed.output_type == out

    def test_mode_specific_validation_errors(self):
        with pytest.raises(ValueError, match="--models"):
            _run_unified_pipeline(_pipeline_args(models=None))
        with pytest.raises(ValueError, match="--source"):
            _run_unified_pipeline(_pipeline_args(mode="absorb", models=None, source=None, target=None))
        with pytest.raises(ValueError, match="coverage-floor"):
            _run_unified_pipeline(
                _pipeline_args(
                    mode="weight-merge",
                    output_type="osmo",
                    models=["pt:a.pt", "pt:b.pt"],
                    coverage_floor=1.1,
                )
            )

    def test_model_ref_parsing(self):
        assert _parse_model_ref("hf:Qwen/Qwen2.5-Coder-0.5B") == ("hf", "Qwen/Qwen2.5-Coder-0.5B")
        assert _parse_model_ref("pt:model.pt") == ("pt", "model.pt")
        assert _parse_model_ref("my_model.pt")[0] == "auto"

    def test_auto_scheme_detection(self, tmp_path):
        pt = tmp_path / "x.pt"
        pt.write_bytes(b"pt")
        onnx = tmp_path / "x.onnx"
        onnx.write_bytes(b"onnx")
        assert _auto_detect_model_scheme(str(pt)) == "pt"
        assert _auto_detect_model_scheme(str(onnx)) == "onnx"
        assert _auto_detect_model_scheme("org/model-id") == "hf"

    def test_parse_onnx_input_shape(self):
        assert _parse_onnx_input_shape("1,128") == (1, 128)
        assert _parse_onnx_input_shape("1x16x64") == (1, 16, 64)
        with pytest.raises(ValueError):
            _parse_onnx_input_shape("0,128")


class TestPipelineBehavior:
    def test_merge_to_osmoimg_uses_compression_profile(self):
        args = _pipeline_args(self_check=False)
        model_a = _make_model(0)
        model_b = _make_model(1)

        class DummyImage:
            name = "pipeline-test"
            parameter_count = 123
            is_encrypted = True

            class Runtime:
                payload_codec = "adaptive-zstd-v1"
                compression_profile = "lossless-max"

            runtime = Runtime()

            def save(self, path, compression_profile=None, **kwargs):
                return Path(path)

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_merge_backend", return_value=_make_model(2)), \
             patch("model_osmosis.format.image.OsmoImage.build", return_value=DummyImage()) as build_mock:
            details = _run_unified_pipeline(args)

        assert details["compression_applied"] is True
        assert details["compression_profile"] == "lossless-max"
        assert build_mock.call_args.kwargs["compression_profile"] == "lossless-max"
        assert build_mock.call_args.kwargs["compression_engine"] == "auto"

    def test_weight_merge_to_osmo_raw_is_unprotected(self):
        args = _pipeline_args(
            mode="weight-merge",
            output_type="osmo",
            models=["pt:a.pt", "pt:b.pt"],
            output="models/weight_merge.osmo",
            self_check=False,
            coverage_floor=0.70,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)
        merged = _make_model(2)
        wm_report = {
            "compatible_tensor_count": 10,
            "skipped_tensor_count": 2,
            "merged_bytes": 4096,
            "coverage_ratio_by_bytes": {"pt:a.pt": 0.90, "pt:b.pt": 0.92},
            "min_coverage_ratio": 0.90,
            "coverage_floor": 0.70,
            "skip_reason_counts": {"missing": 1, "shape_mismatch": 1, "dtype_mismatch": 0},
        }

        class DummyPipeline:
            def obfuscate(self, model, obfuscation_config=None):
                raise AssertionError("weight-merge raw output must not obfuscate")

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_weight_merge_backend", return_value={
            "merged_osmo": merged,
            "report": wm_report,
        }), patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()), \
             patch("model_osmosis.cli._save_osmo_output") as save_mock:
            details = _run_unified_pipeline(args)

        assert details["route"] == "weight-merge"
        assert details["route_reason"] == "exact_param_compatibility"
        assert details["protected"] is False
        assert details["compression_applied"] is False
        assert details["weight_merge_report"]["min_coverage_ratio"] == pytest.approx(0.90)
        save_mock.assert_called_once()

    def test_weight_merge_to_osmoimg_keeps_protected_container(self):
        args = _pipeline_args(
            mode="weight-merge",
            output_type="osmoimg",
            models=["pt:a.pt", "pt:b.pt"],
            output="models/weight_merge.osmoimg",
            self_check=False,
            coverage_floor=0.70,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)
        merged = _make_model(2)

        class DummyImage:
            name = "weight-merge"
            parameter_count = 123
            is_encrypted = True

            class Runtime:
                payload_codec = "adaptive-zstd-v1"
                compression_profile = "lossless-max"
                trust_status = "trusted"
                signer_id = "default"
                key_id = "k1"
                signature_alg = "ed25519"
                signer_backend = "local-keyring"
                transparency_status = None
                artifact_id = "artifact"
                manifest_sha256 = "manifest"
                tensor_index_sha256 = "tensor"

            runtime = Runtime()

            def save(self, path, compression_profile=None, **kwargs):
                return Path(path)

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_weight_merge_backend", return_value={
            "merged_osmo": merged,
            "report": {"min_coverage_ratio": 1.0, "coverage_floor": 0.7},
        }), patch("model_osmosis.format.image.OsmoImage.build", return_value=DummyImage()) as build_mock:
            details = _run_unified_pipeline(args)

        assert details["compression_applied"] is True
        assert details["protected"] is True
        assert details["trust_status"] == "trusted"
        assert build_mock.called

    def test_absorb_to_pytorch_obfuscates_and_saves(self):
        args = _pipeline_args(
            mode="absorb",
            output_type="pytorch",
            models=None,
            source="pt:src.pt",
            target="pt:tgt.pt",
            output="models/absorb_result.pt",
            self_check=False,
        )
        src = _make_model(0)
        tgt = _make_model(1)
        absorbed = _make_model(2)

        class DummyPipeline:
            def absorb(self, source, target, sample_data=None, auto_grow=True):
                return absorbed

            def obfuscate(self, model, obfuscation_config=None):
                return model

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:src.pt", scheme="pt", value="src.pt", model=src),
            LoadedModelRef(raw="pt:tgt.pt", scheme="pt", value="tgt.pt", model=tgt),
        ]), patch("model_osmosis.cli._ensure_absorb_target_supported", return_value=tgt), \
             patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()), \
             patch("model_osmosis.cli._save_model") as save_mock:
            details = _run_unified_pipeline(args)

        assert details["compression_applied"] is False
        save_mock.assert_called_once()

    def test_stack_to_onnx_requires_shape(self):
        args = _pipeline_args(
            mode="stack",
            output_type="onnx",
            output="models/stack.onnx",
            models=["pt:a.pt", "pt:b.pt"],
            onnx_input_shape=None,
            self_check=False,
        )
        m1 = _make_model(0)
        m2 = _make_model(1)
        stacked = _make_model(2)

        class DummyPipeline:
            def stack(self, models, sample_data=None, train_gate=True, top_k=2):
                return stacked

            def obfuscate(self, model, obfuscation_config=None):
                return model

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=m1),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=m2),
        ]), patch("model_osmosis.cli._ensure_stack_expert", side_effect=[m1, m2]), \
             patch("model_osmosis.cli._is_module_available", return_value=True), \
             patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()):
            with pytest.raises(RuntimeError, match="--onnx-input-shape"):
                _run_unified_pipeline(args)

    def test_merge_to_safetensors_calls_safetensors_saver(self):
        args = _pipeline_args(
            output_type="safetensors",
            output="models/merge_result.safetensors",
            self_check=False,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)
        merged = _make_model(2)

        class DummyPipeline:
            def obfuscate(self, model, obfuscation_config=None):
                return model

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_merge_backend", return_value=merged), \
             patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()), \
             patch("model_osmosis.cli._save_safetensors_output") as saver_mock:
            details = _run_unified_pipeline(args)

        assert details["compression_applied"] is False
        saver_mock.assert_called_once()

    def test_pipeline_reports_direct_merge_route(self):
        args = _pipeline_args(
            output_type="pytorch",
            output="models/direct_merge.pt",
            self_check=False,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)
        merged = _make_model(2)

        class DummyPipeline:
            def obfuscate(self, model, obfuscation_config=None):
                return model

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_merge_backend", return_value=merged), \
             patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()), \
             patch("model_osmosis.cli._save_model"):
            details = _run_unified_pipeline(args)

        assert details["route"] == "direct-merge"
        assert details["route_reason"] == "state_dict_keys_and_shapes_match"

    def test_pipeline_reports_cross_merge_route(self):
        args = _pipeline_args(
            output_type="pytorch",
            output="models/cross_merge.pt",
            self_check=False,
        )
        model_a = _make_model(0)
        model_b = nn.Sequential(nn.Linear(4, 4)).eval()
        merged = _make_model(2)

        class DummyPipeline:
            def obfuscate(self, model, obfuscation_config=None):
                return model

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_merge_backend", return_value=merged), \
             patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()), \
             patch("model_osmosis.cli._save_model"):
            details = _run_unified_pipeline(args)

        assert details["route"] == "cross-merge"
        assert details["route_reason"] == "state_dict_incompatible_or_non_stateful_models"

    def test_pipeline_dry_run_does_not_write_output(self, tmp_path):
        output_path = tmp_path / "dry_run.osmoimg"
        args = _pipeline_args(
            output_type="osmoimg",
            output=str(output_path),
            dry_run=True,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_merge_backend") as merge_backend, \
             patch("model_osmosis.format.image.OsmoImage.build") as image_build:
            details = _run_unified_pipeline(args)

        assert details["dry_run"] is True
        assert details["self_check_status"] == "skipped_dry_run"
        assert output_path.exists() is False
        merge_backend.assert_not_called()
        image_build.assert_not_called()

    def test_pipeline_self_check_failure_raises(self):
        args = _pipeline_args(
            output_type="pytorch",
            output="models/self_check_fail.pt",
            self_check=True,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)
        merged = _make_model(2)

        class DummyPipeline:
            def obfuscate(self, model, obfuscation_config=None):
                return model

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_merge_backend", return_value=merged), \
             patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()), \
             patch("model_osmosis.cli._save_model"), \
             patch("model_osmosis.cli._pipeline_self_check", side_effect=RuntimeError("self-check exploded")):
            with pytest.raises(RuntimeError, match="self-check exploded"):
                _run_unified_pipeline(args)

    def test_pipeline_self_check_runs_by_default(self):
        args = _pipeline_args(
            output_type="pytorch",
            output="models/self_check_pass.pt",
            self_check=True,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)
        merged = _make_model(2)

        class DummyPipeline:
            def obfuscate(self, model, obfuscation_config=None):
                return model

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._run_merge_backend", return_value=merged), \
             patch("model_osmosis.OsmosisConfig"), \
             patch("model_osmosis.OsmosisPipeline", return_value=DummyPipeline()), \
             patch("model_osmosis.cli._save_model"), \
             patch("model_osmosis.cli._pipeline_self_check", return_value={
                 "self_check_status": "passed",
                 "self_check_checks": ["artifact_exists"],
             }) as self_check_mock:
            details = _run_unified_pipeline(args)

        assert details["self_check_status"] == "passed"
        self_check_mock.assert_called_once()

    def test_pipeline_preflight_missing_dependency_has_remediation(self):
        args = _pipeline_args(
            output_type="onnx",
            output="models/preflight.onnx",
            onnx_input_shape="1,128",
            self_check=False,
        )
        model_a = _make_model(0)
        model_b = _make_model(1)

        def _module_available(name):
            return name != "onnxruntime"

        with patch("model_osmosis.cli._load_model_ref", side_effect=[
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=model_a),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=model_b),
        ]), patch("model_osmosis.cli._is_module_available", side_effect=_module_available):
            with pytest.raises(RuntimeError, match="onnxruntime"):
                _run_unified_pipeline(args)

    def test_pipeline_report_payload_is_deterministic(self):
        args = _pipeline_args(output_type="osmoimg", output="models/report.osmoimg")
        details = {
            "route": "direct-merge",
            "route_reason": "state_dict_keys_and_shapes_match",
            "reliability_mode": "strict",
            "dry_run": False,
            "resolved_inputs": [
                {"raw": "pt:a.pt", "scheme": "pt", "value": "a.pt"},
                {"raw": "pt:b.pt", "scheme": "pt", "value": "b.pt"},
            ],
            "output_path": Path("models/report.osmoimg"),
            "protected": True,
            "self_check_status": "passed",
            "self_check_checks": ["artifact_exists", "inspect_ok", "verify_ok"],
            "conversion_report": {
                "missing_keys": [],
                "unexpected_keys": [],
                "lossy_casts": [],
                "dtype_transports": [],
            },
            "compression_profile": "lossless-max",
            "payload_codec": "adaptive-zstd-v1",
            "trust_status": "trusted",
        }

        report_a = _pipeline_report_payload(args, details=details, elapsed_seconds=1.2345)
        report_b = _pipeline_report_payload(args, details=details, elapsed_seconds=1.2345)

        assert report_a == report_b
        assert report_a["route"] == "direct-merge"
        assert report_a["conversion_report_counts"]["missing_keys"] == 0
        assert "strategy_engine_mode" in report_a
        assert "recipe_id" in report_a
        assert "selection_latency_ms" in report_a

    def test_pipeline_report_payload_includes_weight_merge_fields(self):
        args = _pipeline_args(
            mode="weight-merge",
            output_type="osmo",
            output="models/report_weight_merge.osmo",
            coverage_floor=0.70,
        )
        details = {
            "route": "weight-merge",
            "route_reason": "exact_param_compatibility",
            "reliability_mode": "strict",
            "dry_run": False,
            "resolved_inputs": [
                {"raw": "pt:b.pt", "scheme": "pt", "value": "b.pt"},
                {"raw": "pt:a.pt", "scheme": "pt", "value": "a.pt"},
            ],
            "output_path": Path("models/report_weight_merge.osmo"),
            "protected": False,
            "self_check_status": "passed",
            "self_check_level": "smoke",
            "self_check_checks": ["artifact_exists"],
            "self_check_skips": [],
            "conversion_report": {
                "missing_keys": [],
                "unexpected_keys": [],
                "lossy_casts": [],
                "dtype_transports": [],
            },
            "compression_profile": "n/a",
            "payload_codec": "n/a",
            "trust_status": "unsigned",
            "weight_merge_report": {
                "compatible_tensor_count": 10,
                "skipped_tensor_count": 3,
                "merged_bytes": 1024,
                "coverage_ratio_by_bytes": {"pt:b.pt": 0.8, "pt:a.pt": 0.9},
                "min_coverage_ratio": 0.8,
                "coverage_floor": 0.7,
                "skip_reason_counts": {"shape_mismatch": 2, "missing": 1, "dtype_mismatch": 0},
            },
        }
        report = _pipeline_report_payload(args, details=details, elapsed_seconds=0.5)
        assert report["mode"] == "weight-merge"
        assert report["weight_merge"]["compatible_tensor_count"] == 10
        assert list(report["weight_merge"]["coverage_ratio_by_bytes"].keys()) == ["pt:a.pt", "pt:b.pt"]
        assert report["weight_merge"]["skip_reason_counts"]["missing"] == 1
        assert "strategy_engine_mode" in report
        assert "recipe_id" in report

    def test_weight_merge_backend_coverage_failure_has_next_command(self):
        loaded = [
            LoadedModelRef(raw="pt:a.pt", scheme="pt", value="a.pt", model=_make_model(0)),
            LoadedModelRef(raw="pt:b.pt", scheme="pt", value="b.pt", model=_make_model(1)),
        ]
        with patch(
            "model_osmosis.format.weight_merge.merge_weights_to_osmo",
            side_effect=RuntimeError("Weight-merge coverage floor not met: min_coverage_ratio=0.20 < coverage_floor=0.70."),
        ):
            with pytest.raises(RuntimeError, match="Next command: osmosis pipeline --mode weight-merge"):
                _run_weight_merge_backend(
                    loaded_refs=loaded,
                    strategy="weighted_average",
                    weights=None,
                    coverage_floor=0.70,
                    output_type="osmoimg",
                    seed=42,
                    allow_lossy_cast=False,
                )

    def test_cmd_pipeline_writes_report_file(self, tmp_path, capsys):
        report_file = tmp_path / "pipeline_report.json"
        args = _pipeline_args(report_file=str(report_file))
        details = {
            "output_path": Path("models/pipeline_test.osmoimg"),
            "compression_applied": True,
            "payload_codec": "adaptive-zstd-v1",
            "compression_profile": "lossless-max",
            "trust_status": "trusted",
            "signer_id": "default",
            "key_id": "key1",
            "signature_alg": "ed25519",
            "signer_backend": "local-keyring",
            "transparency_status": "local_logged",
            "artifact_id": "artifact",
            "manifest_sha256": "manifest",
            "tensor_index_sha256": "tensor",
            "protected": True,
            "conversion_report": {
                "missing_keys": [],
                "unexpected_keys": [],
                "lossy_casts": [],
                "dtype_transports": [],
            },
            "reliability_mode": "strict",
            "route": "direct-merge",
            "route_reason": "state_dict_keys_and_shapes_match",
            "self_check_status": "passed",
            "self_check_checks": ["artifact_exists", "inspect_ok", "verify_ok"],
            "dry_run": False,
            "resolved_inputs": [
                {"raw": "pt:a.pt", "scheme": "pt", "value": "a.pt"},
                {"raw": "pt:b.pt", "scheme": "pt", "value": "b.pt"},
            ],
        }

        with patch("model_osmosis.cli._run_unified_pipeline", return_value=details):
            cmd_pipeline(args)

        _ = capsys.readouterr().out
        payload = json.loads(report_file.read_text(encoding="utf-8"))
        assert payload["mode"] == "merge"
        assert payload["route"] == "direct-merge"
        assert payload["self_check_status"] == "passed"


class TestOptimizerCommands:
    def test_optimize_status_and_reset_json(self, monkeypatch, tmp_path, capsys):
        monkeypatch.setenv("OSMOSIS_OPTIMIZER_HOME", str(tmp_path / "optimizer"))
        record_subsystem_selection(
            subsystem="strategy",
            profile_id="wa_v1",
            pack_version="builtin-pack-v1",
            selector_version="selector-v1",
            selection_latency_ms=7.1,
            quality_ok=True,
            fallback_reason="builtin_pack",
            quality_score=0.5,
        )

        parser = build_parser()
        status_args = parser.parse_args(["optimize-status", "--json"])
        cmd_optimize_status(status_args)
        out = capsys.readouterr().out
        payload = json.loads(out[out.find("{"):])
        assert payload["optimizer_mode"] in {"auto", "off"}
        assert "strategy" in payload["subsystems"]
        assert "cross_merge_classic" in payload["subsystems"]
        assert "cross_merge_llm" in payload["subsystems"]
        assert payload["subsystems"]["strategy"]["active_profile_id"] == "wa_v1"

        reset_args = parser.parse_args(["optimize-reset", "--json"])
        cmd_optimize_reset(reset_args)
        out_reset = capsys.readouterr().out
        reset_payload = json.loads(out_reset[out_reset.find("{"):])
        assert reset_payload["subsystems"]["strategy"]["active_profile_id"] == ""
