"""MCP tools for managing API environments and environment data."""

import json

from mcp.types import TextContent, Tool

from maeris_mcp.auth.token_store import TokenStore
from maeris_mcp.maeris.client import MaerisClient


def _environment_id(env: dict) -> str:
    for key in ["environment_id", "api_environment_id", "id", "env_id"]:
        value = env.get(key)
        if value:
            return str(value)
    return ""


def _environment_name(env: dict) -> str:
    for key in ["name", "environment_name"]:
        value = env.get(key)
        if isinstance(value, str) and value.strip():
            return value
    return ""


def _normalize_environment(env: dict) -> dict:
    return {
        "id": _environment_id(env),
        "name": _environment_name(env),
        "createdAt": env.get("created_at"),
    }


async def _find_environment_by_name(client: MaerisClient, name: str) -> tuple[dict | None, str | None]:
    environments = await client.get_environments()
    matches = [e for e in environments if _environment_name(e).lower() == name.lower()]

    if not matches:
        return None, f"Error: no environment found with name '{name}'"

    if len(matches) > 1:
        short = [_normalize_environment(m) for m in matches]
        return None, (
            f"Error: multiple environments found with name '{name}'. "
            f"Matches: {json.dumps(short)}"
        )

    return matches[0], None


def add_environment_tool() -> Tool:
    return Tool(
        name="add_environment",
        description="Create a new API environment.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Name for the new environment."},
            },
            "required": ["name"],
        },
    )


def get_environments_tool() -> Tool:
    return Tool(
        name="get_environments",
        description="List all API environments.",
        inputSchema={"type": "object", "properties": {}, "required": []},
    )


def edit_environment_tool() -> Tool:
    return Tool(
        name="edit_environment",
        description="Rename an existing environment by name.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Current environment name."},
                "new_name": {"type": "string", "description": "New environment name."},
            },
            "required": ["name", "new_name"],
        },
    )


def delete_environment_tool() -> Tool:
    return Tool(
        name="delete_environment",
        description="Delete an environment by name. Use id to disambiguate when multiple environments share the same name.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Environment name to delete."},
                "id": {"type": "string", "description": "Environment ID to delete directly, bypassing name lookup."},
            },
            "required": [],
        },
    )


def add_environment_data_tool() -> Tool:
    return Tool(
        name="add_environment_data",
        description="Add one or more key-value fields to an environment.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Environment name."},
                "fields": {
                    "type": "array",
                    "description": "Fields to add.",
                    "items": {
                        "type": "object",
                        "properties": {
                            "field_name": {"type": "string"},
                            "field_value": {"type": "string"},
                        },
                        "required": ["field_name", "field_value"],
                    },
                },
            },
            "required": ["name", "fields"],
        },
    )


def get_environment_data_tool() -> Tool:
    return Tool(
        name="get_environment_data",
        description="Get all key-value fields in an environment.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Environment name."},
            },
            "required": ["name"],
        },
    )


def update_environment_data_tool() -> Tool:
    return Tool(
        name="update_environment_data",
        description="Update one field value in an environment.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Environment name."},
                "field_name": {"type": "string", "description": "Field to update."},
                "field_value": {"type": "string", "description": "New field value."},
            },
            "required": ["name", "field_name", "field_value"],
        },
    )


def delete_environment_data_tool() -> Tool:
    return Tool(
        name="delete_environment_data",
        description="Delete one field from an environment.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Environment name."},
                "field_name": {"type": "string", "description": "Field name to delete."},
            },
            "required": ["name", "field_name"],
        },
    )


def select_environment_tool() -> Tool:
    return Tool(
        name="select_environment",
        description="Select and persist current environment by name.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Environment name to select."},
            },
            "required": ["name"],
        },
    )


def get_current_environment_tool() -> Tool:
    return Tool(
        name="get_current_environment",
        description="Get currently selected environment from repo-scoped credentials.",
        inputSchema={"type": "object", "properties": {}, "required": []},
    )


async def handle_add_environment(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    if not name:
        return [TextContent(type="text", text="Error: name is required")]

    async with MaerisClient() as client:
        created = await client.create_environment(name)

    return [TextContent(type="text", text=json.dumps(_normalize_environment(created), indent=2))]


async def handle_get_environments(arguments: dict) -> list[TextContent]:
    async with MaerisClient() as client:
        environments = await client.get_environments()

    result = [_normalize_environment(e) for e in environments]
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_edit_environment(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    new_name = arguments.get("new_name")
    if not name or not new_name:
        return [TextContent(type="text", text="Error: name and new_name are required")]

    async with MaerisClient() as client:
        env, error = await _find_environment_by_name(client, name)
        if error:
            return [TextContent(type="text", text=error)]
        env_id = _environment_id(env)
        updated = await client.update_environment(env_id, new_name)

    result = {
        "id": _environment_id(updated) or env_id,
        "oldName": name,
        "name": _environment_name(updated) or new_name,
    }
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_delete_environment(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    env_id = arguments.get("id")

    if not name and not env_id:
        return [TextContent(type="text", text="Error: name or id is required")]

    async with MaerisClient() as client:
        if not env_id:
            env, error = await _find_environment_by_name(client, name)
            if error:
                return [TextContent(type="text", text=error)]
            env_id = _environment_id(env)
            name = name or _environment_name(env)
        await client.delete_environment(env_id)

    result = {"deleted": True, "id": env_id, "name": name}
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_add_environment_data(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    fields = arguments.get("fields") or []
    if not name:
        return [TextContent(type="text", text="Error: name is required")]
    if not fields:
        return [TextContent(type="text", text="Error: fields is required and must not be empty")]

    async with MaerisClient() as client:
        env, error = await _find_environment_by_name(client, name)
        if error:
            return [TextContent(type="text", text=error)]
        env_id = _environment_id(env)
        response = await client.add_environment_fields(env_id, fields)

    result = {"environmentId": env_id, "name": name, "fieldsAdded": len(fields), "response": response}
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_get_environment_data(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    if not name:
        return [TextContent(type="text", text="Error: name is required")]

    async with MaerisClient() as client:
        env, error = await _find_environment_by_name(client, name)
        if error:
            return [TextContent(type="text", text=error)]
        env_id = _environment_id(env)
        data = await client.get_environment_fields(env_id)

    result = {"environmentId": env_id, "name": name, "data": data}
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_update_environment_data(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    field_name = arguments.get("field_name")
    field_value = arguments.get("field_value")
    if not all([name, field_name, field_value is not None]):
        return [TextContent(type="text", text="Error: name, field_name, and field_value are required")]

    async with MaerisClient() as client:
        env, error = await _find_environment_by_name(client, name)
        if error:
            return [TextContent(type="text", text=error)]
        env_id = _environment_id(env)
        response = await client.update_environment_field(env_id, field_name, field_value)

    result = {
        "environmentId": env_id,
        "name": name,
        "fieldName": field_name,
        "fieldValue": field_value,
        "response": response,
    }
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_delete_environment_data(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    field_name = arguments.get("field_name")
    if not name or not field_name:
        return [TextContent(type="text", text="Error: name and field_name are required")]

    async with MaerisClient() as client:
        env, error = await _find_environment_by_name(client, name)
        if error:
            return [TextContent(type="text", text=error)]
        env_id = _environment_id(env)
        await client.delete_environment_field(env_id, field_name)

    result = {"deleted": True, "environmentId": env_id, "name": name, "fieldName": field_name}
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_select_environment(arguments: dict) -> list[TextContent]:
    name = arguments.get("name")
    if not name:
        return [TextContent(type="text", text="Error: name is required")]

    async with MaerisClient() as client:
        env, error = await _find_environment_by_name(client, name)
        if error:
            return [TextContent(type="text", text=error)]
        env_id = _environment_id(env)
        env_name = _environment_name(env) or name

    TokenStore().save_environment(env_id, env_name)
    result = {"selected": True, "environmentId": env_id, "environmentName": env_name}
    return [TextContent(type="text", text=json.dumps(result, indent=2))]


async def handle_get_current_environment(arguments: dict) -> list[TextContent]:
    store = TokenStore()
    environment_id = store.get_environment_id()
    environment_name = store.get_environment_name()

    if not environment_id:
        result = {
            "environmentId": None,
            "environmentName": None,
            "message": "No current environment selected.",
        }
        return [TextContent(type="text", text=json.dumps(result, indent=2))]

    exists = False
    async with MaerisClient() as client:
        environments = await client.get_environments()
        exists = any(_environment_id(env) == environment_id for env in environments)

    result = {
        "environmentId": environment_id,
        "environmentName": environment_name,
        "exists": exists,
    }
    return [TextContent(type="text", text=json.dumps(result, indent=2))]
