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

JSON-RPC command: start a resumable upload session (REST parity: POST /api/transfer/uploads).
"""

from __future__ import annotations

from typing import Any, Dict

from mcp_proxy_adapter.api.transfer_session_service import (
    TransferPayloadValidationError,
    build_transfer_chunk_transport,
    run_create_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_validation_error_result,
)
from mcp_proxy_adapter.transfer import TransferCompressionError
from mcp_proxy_adapter.transfer import TransferError
from mcp_proxy_adapter.transfer import TransferTooLargeError

_EXAMPLE_SHA256 = "a" * 64


class TransferUploadBeginResult(CommandResult):
    """Success payload: session receipt 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 uploading bytes (PUT).",
            },
            "chunk_path_template": {
                "type": "string",
                "description": (
                    "Relative path template with {transfer_id} and {offset}; "
                    "use same origin and auth headers as JSON-RPC."
                ),
            },
            "protocol_hint": {
                "type": "string",
                "description": "Use the same scheme/host/TLS as the JSON-RPC client.",
            },
        }
        data_props = {
            "transfer_id": {"type": "string", "description": "Opaque session id."},
            "filename": {"type": "string", "description": "Logical filename."},
            "size_bytes": {
                "type": "integer",
                "description": "Total staged size on the wire (compressed if gzip).",
            },
            "checksum_algorithm": {
                "type": "string",
                "description": "Plaintext digest algorithm (phase 1: sha256).",
            },
            "checksum_value": {
                "type": "string",
                "description": "Lowercase hex SHA-256 of plaintext before compression.",
            },
            "compression": {
                "type": "string",
                "enum": ["identity", "gzip"],
                "description": "Compression applied for stored/transferred bytes.",
            },
            "chunk_size": {
                "type": "integer",
                "description": "Server-chosen chunk size upper bound for PUT requests.",
            },
            "offset": {
                "type": "integer",
                "description": "Bytes already received (resume position).",
            },
            "status": {"type": "string", "description": "Session status string."},
            "completed": {
                "type": "boolean",
                "description": "Whether the upload is already finished.",
            },
            "expires_at": {
                "type": ["string", "null"],
                "description": "ISO-8601 expiry time if known.",
            },
            "plaintext_size_bytes": {
                "type": ["integer", "null"],
                "description": "Plaintext length when applicable (e.g. gzip staging).",
            },
            "transport": {
                "type": "object",
                "description": "How to issue chunk PUTs after this command.",
                "properties": transport_props,
                "required": list(transport_props.keys()),
            },
        }
        return {
            "type": "object",
            "description": "Successful transfer_upload_begin result envelope.",
            "properties": {
                "success": {"type": "boolean", "const": True},
                "data": {
                    "type": "object",
                    "description": "Session fields from the store plus transport hints.",
                    "properties": data_props,
                    "required": ["transfer_id", "transport"],
                },
            },
            "required": ["success", "data"],
        }


class TransferUploadBeginCommand(Command):
    """
    Create an upload session for large payloads via HTTP chunk PUTs.

    Same validation and store path as ``POST /api/transfer/uploads``.
    """

    name = "transfer_upload_begin"
    version = "1.0.0"
    descr = (
        "Creates a resumable upload session on the server and returns session metadata "
        "including checksum fields and a chunk URL template. Use this when you need to "
        "send large files: call this command over JSON-RPC (http, https, or mTLS) with "
        "the same API key or Bearer token as other protected commands, then PUT raw "
        "bytes to the returned chunk path on the same origin with identical auth headers. "
        "Progress and job-related events may still be observed on /ws per server config. "
        "The checksum_value must be the SHA-256 (hex) of the plaintext before compression."
    )
    category = "transfer"
    author = "Vasiliy Zdanovskiy"
    email = "vasilyvz@gmail.com"
    result_class = TransferUploadBeginResult

    @classmethod
    def get_schema(cls) -> Dict[str, Any]:
        return {
            "type": "object",
            "description": (
                f"{cls.descr} Invalid hex, wrong compression, or unsupported "
                "checksum_algorithm is rejected with error_type InvalidRequest. "
                "Alignment with REST body fields is exact."
            ),
            "properties": {
                "filename": {
                    "type": "string",
                    "description": "Non-empty logical filename for the upload.",
                },
                "size_bytes": {
                    "type": "integer",
                    "description": (
                        "Non-negative total size on the wire; for gzip, compressed staged size."
                    ),
                },
                "checksum_value": {
                    "type": "string",
                    "description": (
                        "Exactly 64 lowercase hex chars: SHA-256 of plaintext before compression."
                    ),
                },
                "compression": {
                    "type": "string",
                    "enum": ["identity", "gzip"],
                    "description": "identity (raw) or gzip (compressed upload staging).",
                },
                "checksum_algorithm": {
                    "type": "string",
                    "description": "Optional; only sha256 is accepted in phase 1.",
                },
                "chunk_size": {
                    "type": "integer",
                    "description": "Optional preferred chunk size; server may clamp.",
                },
            },
            "required": ["filename", "size_bytes", "checksum_value", "compression"],
            "additionalProperties": False,
            "examples": [
                {
                    "command": "transfer_upload_begin",
                    "params": {
                        "filename": "artifact.bin",
                        "size_bytes": 1024,
                        "checksum_value": _EXAMPLE_SHA256,
                        "compression": "identity",
                    },
                    "description": "Minimal identity upload: checksum is plaintext SHA-256.",
                },
                {
                    "command": "transfer_upload_begin",
                    "params": {
                        "filename": "logs.json.gz",
                        "size_bytes": 2048,
                        "checksum_value": _EXAMPLE_SHA256,
                        "compression": "gzip",
                    },
                    "description": (
                        "Gzip staging: size_bytes is compressed bytes to be sent; "
                        "checksum_value is still plaintext SHA-256."
                    ),
                },
            ],
        }

    async def execute(self, **kwargs: Any) -> Any:
        """
        Args:
            **kwargs: filename, size_bytes, checksum_value, compression, optional fields.

        Returns:
            SuccessResult with session data and transport hints, or ErrorResult on failure.
        """
        context = kwargs.pop("context", {})
        _ = context
        payload: dict[str, object] = {
            "filename": kwargs["filename"],
            "size_bytes": kwargs["size_bytes"],
            "checksum_value": kwargs["checksum_value"],
            "compression": kwargs["compression"],
        }
        if "checksum_algorithm" in kwargs:
            payload["checksum_algorithm"] = kwargs["checksum_algorithm"]
        if "chunk_size" in kwargs:
            payload["chunk_size"] = kwargs["chunk_size"]
        try:
            data = await run_create_upload_session(payload)
        except TransferPayloadValidationError as exc:
            return transfer_validation_error_result(exc.missing_fields)
        except (TransferTooLargeError, TransferCompressionError, TransferError) as exc:
            return transfer_domain_error_result(exc)
        tid = str(data["transfer_id"])
        transport = build_transfer_chunk_transport(direction="upload", transfer_id=tid)
        merged: dict[str, object] = {**data, "transport": transport}
        return TransferUploadBeginResult(merged)
