"""Component CLI commands."""

import sys
import json
import click
from typing import Optional, Any

from cli.utils.config import get_config
from cli.utils.output import format_output, print_error, print_success
from cli.utils.connection import run_command, handle_unity_errors
from cli.utils.parsers import parse_value_safe, parse_json_dict_or_exit
from cli.utils.constants import SEARCH_METHOD_CHOICE_BASIC
from cli.utils.confirmation import confirm_destructive_action


@click.group()
def component():
    """Component operations - add, remove, modify components on GameObjects."""
    pass


@component.command("add")
@click.argument("target")
@click.argument("component_type")
@click.option(
    "--search-method",
    type=SEARCH_METHOD_CHOICE_BASIC,
    default=None,
    help="How to find the target GameObject."
)
@click.option(
    "--properties", "-p",
    default=None,
    help='Initial properties as JSON (e.g., \'{"mass": 5.0}\').'
)
@handle_unity_errors
def add(target: str, component_type: str, search_method: Optional[str], properties: Optional[str]):
    """Add a component to a GameObject.

    \b
    Examples:
        unity-mcp component add "Player" Rigidbody
        unity-mcp component add "-81840" BoxCollider --search-method by_id
        unity-mcp component add "Enemy" Rigidbody --properties '{"mass": 5.0, "useGravity": true}'
    """
    config = get_config()

    params: dict[str, Any] = {
        "action": "add",
        "target": target,
        "componentType": component_type,
    }

    if search_method:
        params["searchMethod"] = search_method
    if properties:
        params["properties"] = parse_json_dict_or_exit(properties, "properties")

    result = run_command("manage_components", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Added {component_type} to '{target}'")


@component.command("remove")
@click.argument("target")
@click.argument("component_type")
@click.option(
    "--search-method",
    type=SEARCH_METHOD_CHOICE_BASIC,
    default=None,
    help="How to find the target GameObject."
)
@click.option(
    "--force", "-f",
    is_flag=True,
    help="Skip confirmation prompt."
)
@click.option(
    "--component-index", "-i",
    type=int,
    default=None,
    help="Zero-based index when multiple components of the same type exist."
)
@handle_unity_errors
def remove(target: str, component_type: str, search_method: Optional[str], force: bool, component_index: Optional[int]):
    """Remove a component from a GameObject.

    \b
    Examples:
        unity-mcp component remove "Player" Rigidbody
        unity-mcp component remove "-81840" BoxCollider --search-method by_id --force
        unity-mcp component remove "Player" BoxCollider --component-index 1
    """
    config = get_config()

    confirm_destructive_action("Remove", component_type, target, force, "from")

    params: dict[str, Any] = {
        "action": "remove",
        "target": target,
        "componentType": component_type,
    }

    if search_method:
        params["searchMethod"] = search_method
    if component_index is not None:
        params["componentIndex"] = component_index

    result = run_command("manage_components", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Removed {component_type} from '{target}'")


@component.command("set")
@click.argument("target")
@click.argument("component_type")
@click.argument("property_name")
@click.argument("value")
@click.option(
    "--search-method",
    type=SEARCH_METHOD_CHOICE_BASIC,
    default=None,
    help="How to find the target GameObject."
)
@click.option(
    "--component-index", "-i",
    type=int,
    default=None,
    help="Zero-based index when multiple components of the same type exist."
)
@handle_unity_errors
def set_property(target: str, component_type: str, property_name: str, value: str, search_method: Optional[str], component_index: Optional[int]):
    """Set a single property on a component.

    \b
    Examples:
        unity-mcp component set "Player" Rigidbody mass 5.0
        unity-mcp component set "Enemy" Transform position "[0, 5, 0]"
        unity-mcp component set "-81840" Light intensity 2.5 --search-method by_id
        unity-mcp component set "Player" BoxCollider size "[2,2,2]" --component-index 1
    """
    config = get_config()

    # Try to parse value as JSON for complex types
    parsed_value = parse_value_safe(value)

    params: dict[str, Any] = {
        "action": "set_property",
        "target": target,
        "componentType": component_type,
        "property": property_name,
        "value": parsed_value,
    }

    if search_method:
        params["searchMethod"] = search_method
    if component_index is not None:
        params["componentIndex"] = component_index

    result = run_command("manage_components", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Set {component_type}.{property_name} = {value}")


@component.command("modify")
@click.argument("target")
@click.argument("component_type")
@click.option(
    "--properties", "-p",
    required=True,
    help='Properties to set as JSON (e.g., \'{"mass": 5.0, "useGravity": false}\').'
)
@click.option(
    "--search-method",
    type=SEARCH_METHOD_CHOICE_BASIC,
    default=None,
    help="How to find the target GameObject."
)
@click.option(
    "--component-index", "-i",
    type=int,
    default=None,
    help="Zero-based index when multiple components of the same type exist."
)
@handle_unity_errors
def modify(target: str, component_type: str, properties: str, search_method: Optional[str], component_index: Optional[int]):
    """Set multiple properties on a component at once.

    \b
    Examples:
        unity-mcp component modify "Player" Rigidbody --properties '{"mass": 5.0, "useGravity": false}'
        unity-mcp component modify "Light" Light --properties '{"intensity": 2.0, "color": [1, 0, 0, 1]}'
        unity-mcp component modify "Player" BoxCollider --properties '{"size": [2,2,2]}' --component-index 1
    """
    config = get_config()

    props_dict = parse_json_dict_or_exit(properties, "properties")

    params: dict[str, Any] = {
        "action": "set_property",
        "target": target,
        "componentType": component_type,
        "properties": props_dict,
    }

    if search_method:
        params["searchMethod"] = search_method
    if component_index is not None:
        params["componentIndex"] = component_index

    result = run_command("manage_components", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Modified {component_type} on '{target}'")
