"""
Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com

JSON-RPC command: read upload session state (REST parity: GET /api/transfer/uploads/{id}).
"""

from __future__ import annotations

from typing import Any, Dict

from mcp_proxy_adapter.api.transfer_session_service import (
    TransferSessionKindMismatch,
    build_transfer_chunk_transport,
    run_get_upload_session,
)
from mcp_proxy_adapter.commands.base import Command, CommandResult
from mcp_proxy_adapter.commands.result import ErrorResult
from mcp_proxy_adapter.commands.transfer_command_support import (
    transfer_domain_error_result,
    transfer_wrong_kind_error_result,
)
from mcp_proxy_adapter.transfer import TransferExpiredError
from mcp_proxy_adapter.transfer import TransferSessionNotFoundError


class TransferUploadStatusResult(CommandResult):
    """Session view for an upload plus chunk transport hints."""

    def __init__(self, data: dict[str, object]) -> None:
        super().__init__(success=True, data=dict(data), error="")

    @classmethod
    def get_schema(cls) -> Dict[str, Any]:
        transport_props = {
            "chunk_method": {
                "type": "string",
                "description": "HTTP method for chunk uploads (PUT).",
            },
            "chunk_path_template": {
                "type": "string",
                "description": "Relative URL template with placeholders for transfer_id and offset.",
            },
            "protocol_hint": {
                "type": "string",
                "description": "Match JSON-RPC client scheme, host, TLS, and auth headers.",
            },
        }
        data_props = {
            "transfer_id": {"type": "string", "description": "Session id."},
            "filename": {"type": "string", "description": "Logical filename."},
            "direction": {
                "type": "string",
                "description": "Must be upload for this command.",
            },
            "size_bytes": {
                "type": "integer",
                "description": "Total expected wire size.",
            },
            "checksum_algorithm": {
                "type": "string",
                "description": "Digest algorithm (sha256).",
            },
            "checksum_value": {
                "type": "string",
                "description": "Expected plaintext SHA-256 hex for verification.",
            },
            "compression": {"type": "string", "description": "identity or gzip."},
            "chunk_size": {"type": "integer", "description": "Configured chunk size."},
            "offset": {"type": "integer", "description": "Bytes received so far."},
            "status": {"type": "string", "description": "Session status."},
            "completed": {"type": "boolean", "description": "Upload finished flag."},
            "expires_at": {
                "type": ["string", "null"],
                "description": "Session expiry ISO time.",
            },
            "plaintext_size_bytes": {
                "type": ["integer", "null"],
                "description": "Plaintext length when tracked.",
            },
            "storage_path": {
                "type": "string",
                "description": "Server staging path for this upload (opaque to clients).",
            },
            "metadata_path": {
                "type": "string",
                "description": "Path to persisted session metadata on the server.",
            },
            "error_message": {
                "type": ["string", "null"],
                "description": "Last error message if session failed.",
            },
            "compressed_storage_path": {
                "type": ["string", "null"],
                "description": "Gzip artifact path when compression is gzip.",
            },
            "transport": {
                "type": "object",
                "description": "Chunk PUT template for continuing the upload.",
                "properties": transport_props,
                "required": list(transport_props.keys()),
            },
        }
        return {
            "type": "object",
            "description": "Successful transfer_upload_status result.",
            "properties": {
                "success": {"type": "boolean", "const": True},
                "data": {
                    "type": "object",
                    "properties": data_props,
                    "required": ["transfer_id", "transport"],
                },
            },
            "required": ["success", "data"],
        }


class TransferUploadStatusCommand(Command):
    """
    Return the current upload session record including checksum and offset.

    Uses the same store lookup as the REST status route.
    """

    name = "transfer_upload_status"
    version = "1.0.0"
    descr = (
        "Returns the live upload session document for a transfer_id, including "
        "checksum_algorithm, checksum_value (plaintext SHA-256 hex), compression, "
        "and offset for resume. Call over JSON-RPC with the same authentication as "
        "help or echo; chunk PUT requests must reuse the same API key or Bearer token "
        "on the same origin. Use after transfer_upload_begin to poll progress or "
        "before issuing the next chunk. Wrong id, expired session, or a download "
        "session id yields stable TransferSessionNotFoundError-style errors in data."
    )
    category = "transfer"
    author = "Vasiliy Zdanovskiy"
    email = "vasilyvz@gmail.com"
    result_class = TransferUploadStatusResult

    @classmethod
    def get_schema(cls) -> Dict[str, Any]:
        return {
            "type": "object",
            "description": (
                f"{cls.descr} Parameter transfer_id is the string returned by "
                "transfer_upload_begin."
            ),
            "properties": {
                "transfer_id": {
                    "type": "string",
                    "description": "Upload session id (e.g. tr_…).",
                },
            },
            "required": ["transfer_id"],
            "additionalProperties": False,
            "examples": [
                {
                    "command": "transfer_upload_status",
                    "params": {"transfer_id": "tr_00000000000000000000000000000000"},
                    "description": "Poll a known upload session by id.",
                },
                {
                    "command": "transfer_upload_status",
                    "params": {"transfer_id": "tr_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
                    "description": "Second example for tooling/tests (synthetic id).",
                },
            ],
        }

    async def execute(self, **kwargs: Any) -> Any:
        """
        Args:
            **kwargs: transfer_id.

        Returns:
            Session dict merged with transport hints, or ErrorResult.
        """
        context = kwargs.pop("context", {})
        _ = context
        transfer_id = str(kwargs["transfer_id"])
        try:
            data = await run_get_upload_session(transfer_id)
        except (TransferSessionNotFoundError, TransferExpiredError) as exc:
            return transfer_domain_error_result(exc)
        except TransferSessionKindMismatch as exc:
            return transfer_wrong_kind_error_result(exc)
        transport = build_transfer_chunk_transport(
            direction="upload", transfer_id=transfer_id
        )
        merged: dict[str, object] = {**data, "transport": transport}
        return TransferUploadStatusResult(merged)
