import json

from conftest import BUCKET_NAME, PREFIX, STS_CREDS

import vcm_file_uploader
from vcm_file_uploader import (  # noqa: F401
    BackupWatchman,
    CompressionInfo,
    JsonlStore,
    LogSegmenter,
    ManifestWriter,
    StateManager,
    STSUploadSession,
    TransferConfig,
    UploadFileEntry,
    UploadPlan,
    UploadResult,
    UploadSummary,
    compress_file,
    maybe_compress,
)


def test_version():
    assert vcm_file_uploader.__version__ == "0.1.0"


def test_s3_bucket_fixture(s3_bucket):
    bucket_name, client = s3_bucket
    buckets = client.list_buckets()["Buckets"]
    assert any(b["Name"] == bucket_name for b in buckets)


def test_all_public_exports():
    """Verify all __all__ entries are importable."""
    for name in vcm_file_uploader.__all__:
        assert hasattr(vcm_file_uploader, name), f"{name} not importable"


class TestSection82UsageFlow:
    """Integration test matching the usage example from design doc Section 8.2."""

    def test_end_to_end_flow(self, mock_s3, tmp_path):
        bucket_name, client = mock_s3

        # 1. Create local files and a plan JSON (simulating backup_watchman output)
        work_dir = tmp_path / "work"
        work_dir.mkdir()
        (work_dir / "t01").mkdir()
        (work_dir / "t01" / "amber.nc").write_bytes(b"trajectory" * 100)
        (work_dir / "t01" / "restart.rst7").write_bytes(b"restart data")
        (work_dir / "config.json").write_text('{"steps": 1000}')

        plan_data = {
            "timestamp": "20260213T123000",
            "files": [
                {
                    "path": "t01/amber.nc",
                    "full_path": str(work_dir / "t01" / "amber.nc"),
                    "size": 1000,
                    "category": "trajectory",
                    "sha256": None,
                    "reason": "new",
                    "multipart": False,
                },
                {
                    "path": "t01/restart.rst7",
                    "full_path": str(work_dir / "t01" / "restart.rst7"),
                    "size": 12,
                    "category": "restart",
                    "sha256": None,
                    "reason": "new",
                    "multipart": False,
                },
                {
                    "path": "config.json",
                    "full_path": str(work_dir / "config.json"),
                    "size": 16,
                    "category": None,
                    "sha256": None,
                    "reason": "new",
                    "multipart": False,
                },
            ],
        }
        plan_file = tmp_path / "upload_20260213T123000.json"
        plan_file.write_text(json.dumps(plan_data))

        # 2. Load plan (as in Section 8.2)
        plan = UploadPlan.from_json(str(plan_file))

        # 3. Create session with STS credentials (as in Section 8.2)
        session = STSUploadSession(
            aws_access_key_id=STS_CREDS["aws_access_key_id"],
            aws_secret_access_key=STS_CREDS["aws_secret_access_key"],
            aws_session_token=STS_CREDS["aws_session_token"],
            region=STS_CREDS["region"],
            bucket=BUCKET_NAME,
            prefix=PREFIX,
        )

        # 4. Upload files
        summary = session.upload_files(plan)
        assert summary.all_succeeded is True
        assert summary.exit_code == 0
        assert len(summary.succeeded) == 3

        # 5. Write manifest (as in Section 8.2, adapted to use ManifestWriter)
        writer = ManifestWriter(session, run_id="test-run")
        writer.add_summary(summary)
        manifest_result = writer.write_manifest()
        assert manifest_result.success is True

        # 6. Close session
        session.close()

        # 7. Verify everything is in S3
        response = client.list_objects_v2(Bucket=bucket_name, Prefix=PREFIX)
        keys = {obj["Key"] for obj in response["Contents"]}
        assert PREFIX + "t01/amber.nc" in keys
        assert PREFIX + "t01/restart.rst7" in keys
        assert PREFIX + "config.json" in keys
        assert writer.manifest_key in keys

        # Verify manifest content
        manifest_obj = client.get_object(Bucket=bucket_name, Key=writer.manifest_key)
        manifest = json.loads(manifest_obj["Body"].read())
        assert manifest["run_id"] == "test-run"
        assert manifest["object_count"] == 3
