"""Material CLI commands."""

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

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_RENDERER


@click.group()
def material():
    """Material operations - create, modify, assign materials."""
    pass


@material.command("info")
@click.argument("path")
@handle_unity_errors
def info(path: str):
    """Get information about a material.

    \b
    Examples:
        unity-mcp material info "Assets/Materials/Red.mat"
    """
    config = get_config()

    result = run_command("manage_material", {
        "action": "get_material_info",
        "materialPath": path,
    }, config)
    click.echo(format_output(result, config.format))


@material.command("create")
@click.argument("path")
@click.option(
    "--shader", "-s",
    default="Standard",
    help="Shader to use (default: Standard)."
)
@click.option(
    "--properties", "-p",
    default=None,
    help='Initial properties as JSON.'
)
@handle_unity_errors
def create(path: str, shader: str, properties: Optional[str]):
    """Create a new material.

    \b
    Examples:
        unity-mcp material create "Assets/Materials/NewMat.mat"
        unity-mcp material create "Assets/Materials/Red.mat" --shader "Universal Render Pipeline/Lit"
        unity-mcp material create "Assets/Materials/Blue.mat" --properties '{"_Color": [0,0,1,1]}'
    """
    config = get_config()

    params: dict[str, Any] = {
        "action": "create",
        "materialPath": path,
        "shader": shader,
    }

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

    result = run_command("manage_material", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Created material: {path}")


@material.command("set-color")
@click.argument("path")
@click.argument("r", type=float)
@click.argument("g", type=float)
@click.argument("b", type=float)
@click.argument("a", type=float, default=1.0)
@click.option(
    "--property", "-p",
    default="_Color",
    help="Color property name (default: _Color)."
)
@handle_unity_errors
def set_color(path: str, r: float, g: float, b: float, a: float, property: str):
    """Set a material's color.

    \b
    Examples:
        unity-mcp material set-color "Assets/Materials/Red.mat" 1 0 0
        unity-mcp material set-color "Assets/Materials/Blue.mat" 0 0 1 0.5
        unity-mcp material set-color "Assets/Materials/Mat.mat" 1 1 0 --property "_BaseColor"
    """
    config = get_config()

    params: dict[str, Any] = {
        "action": "set_material_color",
        "materialPath": path,
        "property": property,
        "color": [r, g, b, a],
    }

    result = run_command("manage_material", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Set color on: {path}")


@material.command("set-property")
@click.argument("path")
@click.argument("property_name")
@click.argument("value")
@handle_unity_errors
def set_property(path: str, property_name: str, value: str):
    """Set a shader property on a material.

    \b
    Examples:
        unity-mcp material set-property "Assets/Materials/Mat.mat" _Metallic 0.5
        unity-mcp material set-property "Assets/Materials/Mat.mat" _Smoothness 0.8
        unity-mcp material set-property "Assets/Materials/Mat.mat" _MainTex "Assets/Textures/Tex.png"
    """
    config = get_config()

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

    params: dict[str, Any] = {
        "action": "set_material_shader_property",
        "materialPath": path,
        "property": property_name,
        "value": parsed_value,
    }

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


@material.command("assign")
@click.argument("material_path")
@click.argument("target")
@click.option(
    "--search-method",
    type=SEARCH_METHOD_CHOICE_RENDERER,
    default=None,
    help="How to find the target GameObject."
)
@click.option(
    "--slot", "-s",
    default=0,
    type=int,
    help="Material slot index (default: 0)."
)
@click.option(
    "--mode", "-m",
    type=click.Choice(["shared", "instance", "property_block", "create_unique"]),
    default="shared",
    help="Assignment mode."
)
@handle_unity_errors
def assign(material_path: str, target: str, search_method: Optional[str], slot: int, mode: str):
    """Assign a material to a GameObject's renderer.

    \b
    Examples:
        unity-mcp material assign "Assets/Materials/Red.mat" "Cube"
        unity-mcp material assign "Assets/Materials/Blue.mat" "Player" --mode instance
        unity-mcp material assign "Assets/Materials/Mat.mat" "-81840" --search-method by_id --slot 1
    """
    config = get_config()

    params: dict[str, Any] = {
        "action": "assign_material_to_renderer",
        "materialPath": material_path,
        "target": target,
        "slot": slot,
        "mode": mode,
    }

    if search_method:
        params["searchMethod"] = search_method

    result = run_command("manage_material", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Assigned material to: {target}")


@material.command("set-renderer-color")
@click.argument("target")
@click.argument("r", type=float)
@click.argument("g", type=float)
@click.argument("b", type=float)
@click.argument("a", type=float, default=1.0)
@click.option(
    "--search-method",
    type=SEARCH_METHOD_CHOICE_RENDERER,
    default=None,
    help="How to find the target GameObject."
)
@click.option(
    "--mode", "-m",
    type=click.Choice(["shared", "instance", "property_block", "create_unique"]),
    default="property_block",
    help="Modification mode (default: property_block — use create_unique for persistent per-object material)."
)
@handle_unity_errors
def set_renderer_color(target: str, r: float, g: float, b: float, a: float, search_method: Optional[str], mode: str):
    """Set a renderer's material color directly.

    \b
    Examples:
        unity-mcp material set-renderer-color "Cube" 1 0 0
        unity-mcp material set-renderer-color "Player" 0 1 0 --mode instance
    """
    config = get_config()

    params: dict[str, Any] = {
        "action": "set_renderer_color",
        "target": target,
        "color": [r, g, b, a],
        "mode": mode,
    }

    if search_method:
        params["searchMethod"] = search_method

    result = run_command("manage_material", params, config)
    click.echo(format_output(result, config.format))
    if result.get("success"):
        print_success(f"Set renderer color on: {target}")
