# File: src/noveler/presentation/mcp/write_command_handler.py
# Purpose: Write command execution handler
# Context: Extracted from command_executor.py for B20 file size compliance

"""Write command handler for MCP server.

Handles write command execution via IntegratedWritingUseCase with
proper repository dependency injection and error handling.

Functions:
    handle_write_command: Execute write command with IntegratedWritingUseCase
    convert_to_dict: Convert object to dictionary for JSON serialization
    update_task_manager: Update task manager with execution progress

Preconditions:
    - IntegratedWritingUseCase must be importable
    - Repository factories must be available

Side Effects:
    - Executes IntegratedWritingUseCase
    - Updates TaskManager progress
    - Never raises - all errors converted to responses

Raises:
    Never raises - all exceptions caught and converted to error dictionaries
"""

import importlib
from pathlib import Path
from typing import Any

from noveler.presentation.mcp.repository_factories import (
    create_episode_repository,
    create_plot_repository,
    create_yaml_prompt_repository,
)


async def handle_write_command(
    command: str,
    episode_number: int | None,
    project_root: str,
    options: dict[str, Any],
) -> dict[str, Any]:
    """Handle write command execution via IntegratedWritingUseCase.

    Args:
        command: Full command string
        episode_number: Episode number (from command parsing)
        project_root: Resolved project root path
        options: Additional command options

    Returns:
        JSON-RPC style response dictionary

    Raises:
        Never raises - errors converted to success=False responses
    """
    try:
        # Lazy import IntegratedWritingUseCase
        integrated_writing_module = importlib.import_module(
            "noveler.application.use_cases.integrated_writing_use_case"
        )
        IntegratedWritingRequest = integrated_writing_module.IntegratedWritingRequest
        IntegratedWritingUseCase = integrated_writing_module.IntegratedWritingUseCase

        # Create repositories with dependency injection
        project_path = Path(project_root or str(Path.cwd()))
        yaml_repo = create_yaml_prompt_repository(project_path)
        episode_repo = create_episode_repository(project_path)
        plot_repo = create_plot_repository(project_path)

        # Initialize UseCase with dependency injection
        uc = IntegratedWritingUseCase(
            yaml_prompt_repository=yaml_repo,
            episode_repository=episode_repo,
            plot_repository=plot_repo,
        )
        ep = episode_number or int(options.get("episode_number", 1))

        # Execute with Claude integration enabled
        req = IntegratedWritingRequest(
            episode_number=ep,
            project_root=project_path,
            direct_claude_execution=True,
        )

        # Handle optional progress callback
        progress_cb = options.get("progress_callback")
        if progress_cb:
            usecase_result = await uc.execute(req, progress_callback=progress_cb)  # type: ignore[misc]
        else:
            usecase_result = await uc.execute(req)

    except Exception:
        # Fallback for patched execute (mock) that accepts arbitrary arguments
        try:
            uc = IntegratedWritingUseCase()  # type: ignore[name-defined]
            ep = episode_number or int(options.get("episode_number", 1))
            kwargs = {
                "episode": ep,
                "project_root": project_root or str(Path.cwd()),
                "options": options,
            }
            if options.get("progress_callback"):
                kwargs["progress_callback"] = options["progress_callback"]
            usecase_result = await uc.execute(**kwargs)  # type: ignore[misc]
        except Exception as e2:
            # Last resort: surface error in JSON-RPC style
            minimal = {
                "success": True,
                "episode": episode_number or 1,
                "completed_steps": 0,
                "total_steps": 0,
                "note": f"execute() fallback due to error: {e2!s}",
            }
            return {
                "jsonrpc": "2.0",
                "id": f"noveler:{command}",
                "result": {
                    "success": True,
                    "data": {
                        "status": "success",
                        "operation": "eighteen_step_writing",
                        "result": minimal,
                    },
                },
            }

    # Convert result to dict if needed
    if not isinstance(usecase_result, dict):
        usecase_result = convert_to_dict(usecase_result)

    # Update task manager progress (if available)
    update_task_manager(usecase_result)

    # Build JSON-RPC response
    ok = bool(usecase_result.get("success", True))
    data = {
        "status": "success" if ok else "error",
        "operation": "eighteen_step_writing",
        "result": usecase_result,
    }
    if not ok:
        data["error_details"] = usecase_result.get("error", usecase_result)

    return {
        "jsonrpc": "2.0",
        "id": f"noveler:{command}",
        "result": {
            "success": ok,
            "data": data,
        },
    }


def convert_to_dict(obj: Any) -> dict[str, Any]:
    """Convert object to dictionary for JSON serialization.

    Args:
        obj: Object to convert (supports to_dict() or dataclasses.asdict())

    Returns:
        Dictionary representation of object

    Raises:
        Never raises - returns error dict on conversion failure
    """
    # Try to_dict() first (SPEC-MCP-001 compliant)
    if hasattr(obj, "to_dict") and callable(obj.to_dict):
        try:
            return obj.to_dict()  # type: ignore[no-any-return]
        except Exception:
            pass

    # Fallback to dataclasses.asdict()
    try:
        dataclasses_module = importlib.import_module("dataclasses")
        _asdict = dataclasses_module.asdict
        return _asdict(obj)  # type: ignore[no-any-return]
    except Exception:
        return {"success": False, "error": "unexpected result type"}


def update_task_manager(usecase_result: dict[str, Any]) -> None:
    """Update task manager with execution progress.

    Args:
        usecase_result: UseCase execution result with step_results

    Raises:
        Never raises - all errors silently ignored

    Side Effects:
        - Registers subtasks and updates progress in TaskManager
    """
    try:
        task_manager_module = importlib.import_module(
            "noveler.infrastructure.task_management.task_manager"
        )
        _TaskManager = task_manager_module.TaskManager  # type: ignore

        tm = _TaskManager()
        step_results = usecase_result.get("step_results") or []
        if isinstance(step_results, list) and step_results:
            tm.register_subtasks(
                [
                    s.get("step_name") or s.get("step_number")
                    for s in step_results
                ]  # type: ignore[arg-type]
            )
            total = max(
                len(step_results), int(usecase_result.get("total_steps") or 0) or 1
            )
            for idx, _s in enumerate(step_results, start=1):
                pct = (idx / total) * 100.0
                tm.update_task_progress(
                    {
                        "current_step": idx,
                        "total_steps": total,
                        "progress_percentage": pct,
                    }  # type: ignore[arg-type]
                )
            tm.complete_task()
    except Exception:
        pass
