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

JSON-RPC command: read download session (REST parity: GET /api/transfer/downloads/{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_download_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 TransferDownloadStatusResult(CommandResult):
    """Download session view with GET 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 download (GET).",
            },
            "chunk_path_template": {
                "type": "string",
                "description": "Template including offset and limit query placeholders.",
            },
            "protocol_hint": {
                "type": "string",
                "description": "Match JSON-RPC client origin and credentials.",
            },
        }
        data_props = {
            "transfer_id": {"type": "string", "description": "Download session id."},
            "filename": {"type": "string", "description": "Filename."},
            "direction": {"type": "string", "description": "download."},
            "size_bytes": {"type": "integer", "description": "Wire size."},
            "checksum_algorithm": {"type": "string", "description": "sha256."},
            "checksum_value": {
                "type": "string",
                "description": "Plaintext file SHA-256 hex for client verification.",
            },
            "compression": {"type": "string", "description": "identity or gzip."},
            "chunk_size": {"type": "integer", "description": "Chunk read size."},
            "offset": {"type": "integer", "description": "Bytes already delivered."},
            "status": {"type": "string", "description": "Session status."},
            "completed": {"type": "boolean", "description": "All bytes read."},
            "expires_at": {"type": ["string", "null"], "description": "Expiry time."},
            "plaintext_size_bytes": {
                "type": ["integer", "null"],
                "description": "Uncompressed size when gzip.",
            },
            "storage_path": {
                "type": "string",
                "description": "Absolute source file path on the server.",
            },
            "metadata_path": {
                "type": "string",
                "description": "Session metadata file path.",
            },
            "error_message": {
                "type": ["string", "null"],
                "description": "Failure message if any.",
            },
            "compressed_storage_path": {
                "type": ["string", "null"],
                "description": "Compressed artifact path for gzip downloads.",
            },
            "job_id": {
                "type": ["string", "null"],
                "description": "Optional queue job correlation when set at session creation.",
            },
            "correlation_id": {
                "type": ["string", "null"],
                "description": "Opaque client correlation id when set at session creation.",
            },
            "command": {
                "type": ["string", "null"],
                "description": "Optional command name when set at session creation.",
            },
            "inbound_transfer_id": {
                "type": ["string", "null"],
                "description": "Optional related upload session id.",
            },
            "delete_source_on_ack": {
                "type": "boolean",
                "description": "If true, transfer_ack may delete the source file under policy.",
            },
            "transport": {
                "type": "object",
                "description": "Resume GET requests using offset and limit.",
                "properties": transport_props,
                "required": list(transport_props.keys()),
            },
        }
        return {
            "type": "object",
            "description": "Successful transfer_download_status result.",
            "properties": {
                "success": {"type": "boolean", "const": True},
                "data": {
                    "type": "object",
                    "properties": data_props,
                    "required": ["transfer_id", "transport"],
                },
            },
            "required": ["success", "data"],
        }


class TransferDownloadStatusCommand(Command):
    """
    Return download session fields for verifying checksums while streaming.

    Same JSON as REST GET for download sessions, plus transport hints.
    """

    name = "transfer_download_status"
    version = "1.0.0"
    descr = (
        "Fetches the current download session including checksum_value (plaintext "
        "SHA-256), compression, offset, and size_bytes so clients can validate "
        "aggregated data. Authenticate like other protected JSON-RPC commands; "
        "chunk GETs must send the same API key or Bearer token. Use together with "
        "transfer_download_begin and GET .../chunks. Wrong session type or missing "
        "id returns stable TransferSessionNotFoundError-style data matching HTTP."
    )
    category = "transfer"
    author = "Vasiliy Zdanovskiy"
    email = "vasilyvz@gmail.com"
    result_class = TransferDownloadStatusResult

    @classmethod
    def get_schema(cls) -> Dict[str, Any]:
        return {
            "type": "object",
            "description": (
                f"{cls.descr} Parameter transfer_id comes from transfer_download_begin."
            ),
            "properties": {
                "transfer_id": {
                    "type": "string",
                    "description": "Download session id.",
                },
            },
            "required": ["transfer_id"],
            "additionalProperties": False,
            "examples": [
                {
                    "command": "transfer_download_status",
                    "params": {"transfer_id": "tr_00000000000000000000000000000000"},
                    "description": "Poll download progress by session id.",
                },
                {
                    "command": "transfer_download_status",
                    "params": {"transfer_id": "tr_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},
                    "description": "Second example id for schema/tests.",
                },
            ],
        }

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

        Returns:
            Session dict with transport or ErrorResult.
        """
        context = kwargs.pop("context", {})
        _ = context
        transfer_id = str(kwargs["transfer_id"])
        try:
            data = await run_get_download_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="download", transfer_id=transfer_id
        )
        merged: dict[str, object] = {**data, "transport": transport}
        return TransferDownloadStatusResult(merged)
