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

JSON-RPC command: finalize upload and verify digest (REST parity: POST .../complete).
"""

from __future__ import annotations

from typing import Any, Dict

from mcp_proxy_adapter.api.transfer_session_service import (
    TransferSessionKindMismatch,
    run_complete_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 TransferChecksumMismatchError
from mcp_proxy_adapter.transfer import TransferCompressionError
from mcp_proxy_adapter.transfer import TransferError
from mcp_proxy_adapter.transfer import TransferExpiredError
from mcp_proxy_adapter.transfer import TransferSessionNotFoundError


class TransferUploadCompleteResult(CommandResult):
    """Receipt after server-side digest verification."""

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

    @classmethod
    def get_schema(cls) -> Dict[str, Any]:
        data_props = {
            "transfer_id": {"type": "string", "description": "Completed session id."},
            "filename": {"type": "string", "description": "Logical filename."},
            "size_bytes": {"type": "integer", "description": "Final wire size."},
            "checksum_algorithm": {"type": "string", "description": "sha256."},
            "checksum_value": {
                "type": "string",
                "description": "Verified plaintext SHA-256 hex.",
            },
            "compression": {"type": "string", "description": "identity or gzip."},
            "chunk_size": {"type": "integer", "description": "Chunk size used."},
            "offset": {
                "type": "integer",
                "description": "Final offset (equals size when done).",
            },
            "status": {
                "type": "string",
                "description": "Terminal status (e.g. uploaded).",
            },
            "completed": {
                "type": "boolean",
                "const": True,
                "description": "Always true on success.",
            },
            "expires_at": {
                "type": ["string", "null"],
                "description": "Session metadata expiry.",
            },
            "plaintext_size_bytes": {
                "type": ["integer", "null"],
                "description": "Plaintext length when applicable.",
            },
        }
        return {
            "type": "object",
            "description": "Successful transfer_upload_complete result (no further chunks).",
            "properties": {
                "success": {"type": "boolean", "const": True},
                "data": {
                    "type": "object",
                    "properties": data_props,
                    "required": ["transfer_id", "checksum_value", "status"],
                },
            },
            "required": ["success", "data"],
        }


class TransferUploadCompleteCommand(Command):
    """
    Verify plaintext checksum and mark the upload complete.

    On mismatch the error payload includes error_type TransferChecksumMismatchError.
    """

    name = "transfer_upload_complete"
    version = "1.0.0"
    descr = (
        "Finalizes an upload after all bytes were sent via PUT chunks. The server "
        "recomputes the plaintext SHA-256 and compares it to checksum_value from "
        "the session; mismatch surfaces TransferChecksumMismatchError in the command "
        "error data, matching REST. Requires the same JSON-RPC authentication as "
        "other protected commands. After success, no further chunk PUTs apply. "
        "Use when offset reached size_bytes and you want the staged file promoted."
    )
    category = "transfer"
    author = "Vasiliy Zdanovskiy"
    email = "vasilyvz@gmail.com"
    result_class = TransferUploadCompleteResult

    @classmethod
    def get_schema(cls) -> Dict[str, Any]:
        return {
            "type": "object",
            "description": (
                f"{cls.descr} Domain errors use the same error_type strings as "
                "build_transfer_error_response / HTTP JSON."
            ),
            "properties": {
                "transfer_id": {
                    "type": "string",
                    "description": "Upload session to complete.",
                },
            },
            "required": ["transfer_id"],
            "additionalProperties": False,
            "examples": [
                {
                    "command": "transfer_upload_complete",
                    "params": {"transfer_id": "tr_00000000000000000000000000000000"},
                    "description": "Complete after full identity upload and matching digest.",
                },
                {
                    "command": "transfer_upload_complete",
                    "params": {"transfer_id": "tr_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
                    "description": "Second synthetic id example for clients and tests.",
                },
            ],
        }

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

        Returns:
            Receipt on success; ErrorResult with TransferChecksumMismatchError on mismatch.
        """
        context = kwargs.pop("context", {})
        _ = context
        transfer_id = str(kwargs["transfer_id"])
        try:
            data = await run_complete_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)
        except (
            TransferChecksumMismatchError,
            TransferCompressionError,
            TransferError,
        ) as exc:
            return transfer_domain_error_result(exc)
        return TransferUploadCompleteResult(data)
