"""ManifestWriter — build and upload run manifests."""

from __future__ import annotations

import json
import logging
import tempfile
import uuid
from dataclasses import asdict
from datetime import datetime, timezone
from typing import TYPE_CHECKING

from vcm_file_uploader._types import UploadResult, UploadSummary

if TYPE_CHECKING:
    from vcm_file_uploader.session import STSUploadSession

logger = logging.getLogger(__name__)


class ManifestWriter:
    """Builds and uploads run manifests to S3.

    Records uploaded objects with sizes, timestamps, checksums,
    and compression metadata. Writes the manifest as the final
    object in the upload session.
    """

    def __init__(self, session: STSUploadSession, run_id: str | None = None) -> None:
        self._session = session
        self.run_id = run_id or uuid.uuid4().hex[:12]
        self._entries: list[dict] = []

    def add_result(self, result: UploadResult) -> None:
        """Record a single upload result."""
        if not result.success:
            return
        entry: dict = {
            "path": result.local_path,
            "uploaded_key": result.s3_key,
            "size": result.size,
            "uploaded_at": result.uploaded_at.isoformat(),
        }
        if result.compression is not None:
            entry["compression"] = asdict(result.compression)
        self._entries.append(entry)

    def add_summary(self, summary: UploadSummary) -> None:
        """Record all successful results from an UploadSummary."""
        for result in summary.succeeded:
            self.add_result(result)

    @property
    def manifest_key(self) -> str:
        return f"{self._session.prefix}manifests/uploader_manifest_{self.run_id}.json"

    def to_dict(self) -> dict:
        """Return the manifest as a dictionary."""
        return {
            "run_id": self.run_id,
            "created_at": datetime.now(timezone.utc).isoformat(),
            "bucket": self._session.bucket,
            "prefix": self._session.prefix,
            "object_count": len(self._entries),
            "objects": self._entries,
        }

    def write_manifest(self) -> UploadResult:
        """Serialize the manifest to JSON and upload to S3."""
        manifest = self.to_dict()
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".json", delete=False
        ) as f:
            json.dump(manifest, f, indent=2)
            f.write("\n")
            tmp_path = f.name

        result = self._session.upload_file(tmp_path, self.manifest_key)
        logger.info("Manifest uploaded to s3://%s/%s", self._session.bucket, self.manifest_key)
        return result
